#include "global.h"
#include "item_use.h"
#include "battle.h"
#include "battle_anim.h"
#include "battle_pyramid.h"
#include "battle_pyramid_bag.h"
#include "berry.h"
#include "berry_powder.h"
#include "bike.h"
#include "coins.h"
#include "data.h"
#include "event_data.h"
#include "event_object_lock.h"
#include "event_object_movement.h"
#include "event_scripts.h"
#include "fieldmap.h"
#include "field_effect.h"
#include "field_player_avatar.h"
#include "field_screen_effect.h"
#include "field_weather.h"
#include "item.h"
#include "item_menu.h"
#include "item_use.h"
#include "mail.h"
#include "main.h"
#include "menu.h"
#include "menu_helpers.h"
#include "metatile_behavior.h"
#include "overworld.h"
#include "palette.h"
#include "party_menu.h"
#include "pokeblock.h"
#include "pokemon.h"
#include "script.h"
#include "sound.h"
#include "strings.h"
#include "string_util.h"
#include "task.h"
#include "text.h"
#include "constants/event_bg.h"
#include "constants/event_objects.h"
#include "constants/item_effects.h"
#include "constants/items.h"
#include "constants/songs.h"
#include "bg.h"
#include "malloc.h"
#include "window.h"
#include "gpu_regs.h"
#include "scanline_effect.h"
#include "text_window.h"
#include "diploma.h"
#include "main_menu.h"
#include "frontier_pass.h"
#include "decompress.h"
#include "pokemon_icon.h"
#include "graphics.h"
#include "international_string_util.h"
#include "party_menu.h"
#include "money.h"
#include "tv.h"
#include "dexnav.h"
#include "fme.h"

static void SetUpItemUseCallback(u8 taskId);
static void FieldCB_UseItemOnField(void);
static void Task_CallItemUseOnFieldCallback(u8 taskId);
static void Task_UseItemfinder(u8 taskId);
static void Task_CloseItemfinderMessage(u8 taskId);
static void Task_HiddenItemNearby(u8 taskId);
static void Task_StandingOnHiddenItem(u8 taskId);
static bool8 ItemfinderCheckForHiddenItems(const struct MapEvents *, u8);
static u8 GetDirectionToHiddenItem(s16 distanceX, s16 distanceY);
static void PlayerFaceHiddenItem(u8 a);
static void CheckForHiddenItemsInMapConnection(u8 taskId);
static void sub_80FDC00(u8 taskId);
static void ItemUseOnFieldCB_Bike(u8 taskId);
static void ItemUseOnFieldCB_Rod(u8);
static void ItemUseOnFieldCB_Itemfinder(u8);
static void ItemUseOnFieldCB_Berry(u8 taskId);
static void ItemUseOnFieldCB_WailmerPailBerry(u8 taskId);
static void ItemUseOnFieldCB_WailmerPailSudowoodo(u8 taskId);
static bool8 TryToWaterSudowoodo(void);
static void BootUpSoundTMHM(u8 taskId);
static void Task_ShowTMHMContainedMessage(u8 taskId);
static void UseTMHMYesNo(u8 taskId);
static void UseTMHM(u8 taskId);
static void Task_StartUseRepel(u8 taskId);
static void Task_UseRepel(u8 taskId);
static void Task_CloseCantUseKeyItemMessage(u8 taskId);
static void SetDistanceOfClosestHiddenItem(u8 taskId, s16 x, s16 y);
static void CB2_OpenPokeblockCaseOnField(void);
static void CB2_PowderBoxMain(void);
void CB2_PhoneMain(void);
static void CB2_ShowPowderBoxMain(void);
static void CB2_ShowPhoneMain(void);
static void Task_FuncFadeIn(u8 taskId);
static void Task_FuncProcessInputMain(u8 taskId);
static void Task_FuncProcessInputFunc(u8 taskId);
static void Task_FuncBuyDexNev(u8 taskId);
static void Task_FuncProcessInputBuy(u8 taskId);
static void Task_FuncProcessInputCount(u8 taskId);
static void Task_FuncProcessInputBuySuccess(u8 taskId);
static void Task_NeedMoreRoom(u8 taskId);
static void Task_NoEnoughMoney(u8 taskId);
static void Task_NoWildMonHere(u8 taskId);
static void Task_FuncFadeOut(u8 taskId);
static void Task_ChangeBg(u8 taskId);
static void Task_PrintLeastOne(u8 taskId);
static void Task_FuncProcessInputEVIV(u8 taskId);
static void Task_FuncOpenPC(u8 taskId);
static void Task_FuncProcessNoQualification(u8 taskId);
static void DrawTextWinMain(void);
static void DrawOptionsWinMain(void);
static void DrawTextWinFunc(void);
static void DrawOptionsWinFunc(void);
static void DrawTextWinCount(u8 count);
static void DrawTextWinBuy(void);
static void DrawOptionsWinBuy(s16 slot, u8 count);
static void DrawTextWinEVIV(void);
static void DrawOptionsWinEVIV(u8 slot, u8 type);
static void ChangeCursorPos(u8 spriteId, u8 selection, u8 section);
static const void* GetTiles(u8 id);
static const void* GetTileMap(u8 id);
static const void* GetPalette(u8 id);
static const u8 GetMode(u8 id);
static void MainCB2(void);
static void VBlankCB(void);
static void CreatePlayerOW(u8 taskId);
static void DrawTextWinPowderBox(void);
static void Task_PowderBoxFadeIn(u8 taskId);
static void Task_PowderBoxProcessInput(u8 taskId);
static void Task_ChangeOWSuccess(u8 taskId);
static void Task_ChangeOWFailed(u8 taskId);
static void PrintOWName(u8 appearance);

// EWRAM variables
EWRAM_DATA static void(*sItemUseOnFieldCB)(u8 taskId) = NULL;
EWRAM_DATA static void* gPhonePtr = NULL;
EWRAM_DATA bool8 gIsFromPhone = FALSE;

static const u8 OWNames[PLAYER_APPEARANCE_COUNT][GENDER_COUNT][7];

struct TileMaps
{
    const void* tiles;
    const void* tilemap;
    const void* pal;
    const u8 mode;
};

static const struct TileMaps gTileMaps[] = {
    //tiles		        tilemap   			pal					mode
    {sDiplomaTiles, 	sDiplomaTilemap,	sDiplomaPalettes,	1},
    {sDiplomaTiles, 	sDiplomaTilemap,	sDiplomaPalettes,	0},
	{sDiplomaTilesFR, 	sDiplomaTilemapFR,	sDiplomaPalettesFR,	1},
    {sDiplomaTilesFR, 	sDiplomaTilemapFR,	sDiplomaPalettesFR,	0},
};

// Below is set TRUE by UseRegisteredKeyItemOnField
#define tUsingRegisteredKeyItem  data[3]

// .rodata

static const MainCallback sItemUseCallbacks[] =
{
    CB2_ShowPartyMenuForItemUse,
    CB2_ReturnToField,
    NULL,
};

static const u8 sClockwiseDirections[] = {DIR_NORTH, DIR_EAST, DIR_SOUTH, DIR_WEST};

static const struct YesNoFuncTable sUseTMHMYesNoFuncTable =
{
    .yesFunc = UseTMHM,
    .noFunc = BagMenu_InitListsMenu,
};

// .text

static void SetUpItemUseCallback(u8 taskId)
{
    u8 type;
    if (gSpecialVar_ItemId == ITEM_ENIGMA_BERRY)
        type = gTasks[taskId].data[4] - 1;
    else
        type = ItemId_GetType(gSpecialVar_ItemId) - 1;


    if (!InBattlePyramid())
    {
        if (gMain.useInBag == FALSE)
        {
            SetMainCallback2(sItemUseCallbacks[type]);
        }
        else
        {
            gBagMenu->exitCallback = sItemUseCallbacks[type];
            Task_FadeAndCloseBagMenu(taskId);
        }
    }
    else
    {
        gPyramidBagResources->callback2 = sItemUseCallbacks[type];
        CloseBattlePyramidBagAndSetCallback(taskId);
    }
}

static void SetUpItemUseOnFieldCallback(u8 taskId)
{
    if (gTasks[taskId].tUsingRegisteredKeyItem != TRUE)
    {
        gFieldCallback = FieldCB_UseItemOnField;
        SetUpItemUseCallback(taskId);
    }
    else
        sItemUseOnFieldCB(taskId);
}

static void FieldCB_UseItemOnField(void)
{
    FadeInFromBlack();
    CreateTask(Task_CallItemUseOnFieldCallback, 8);
}

static void Task_CallItemUseOnFieldCallback(u8 taskId)
{
    if (IsWeatherNotFadingIn() == 1)
        sItemUseOnFieldCB(taskId);
}

static void DisplayCannotUseItemMessage(u8 taskId, bool8 isUsingRegisteredKeyItemOnField, const u8 *str)
{
    StringExpandPlaceholders(gStringVar4, str);
    if (!isUsingRegisteredKeyItemOnField)
    {
        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, gStringVar4, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, gText_DadsAdvice, Task_CloseBattlePyramidBagMessage);
    }
    else
        DisplayItemMessageOnField(taskId, gStringVar4, Task_CloseCantUseKeyItemMessage);
}

static void DisplayDadsAdviceCannotUseItemMessage(u8 taskId, bool8 isUsingRegisteredKeyItemOnField)
{
    DisplayCannotUseItemMessage(taskId, isUsingRegisteredKeyItemOnField, gText_DadsAdvice);
}

static void DisplayCannotDismountBikeMessage(u8 taskId, bool8 isUsingRegisteredKeyItemOnField)
{
    DisplayCannotUseItemMessage(taskId, isUsingRegisteredKeyItemOnField, gText_CantDismountBike);
}

static void Task_CloseCantUseKeyItemMessage(u8 taskId)
{
    ClearDialogWindowAndFrame(0, 1);
    DestroyTask(taskId);
    ScriptUnfreezeObjectEvents();
    ScriptContext2_Disable();
}

u8 CheckIfItemIsTMHMOrEvolutionStone(u16 itemId)
{
    if (ItemId_GetFieldFunc(itemId) == ItemUseOutOfBattle_TMHM)
        return 1;
    else if (ItemId_GetFieldFunc(itemId) == ItemUseOutOfBattle_EvolutionStone)
        return 2;
    else
        return 0;
}

// Mail in the bag menu can't have a message but it can be checked (view the mail background, no message)
static void CB2_CheckMail(void)
{
    struct MailStruct mail;
    mail.itemId = gSpecialVar_ItemId;
    ReadMail(&mail, CB2_ReturnToBagMenuPocket, 0);
}

void ItemUseOutOfBattle_Mail(u8 taskId)
{
    gBagMenu->exitCallback = CB2_CheckMail;
    Task_FadeAndCloseBagMenu(taskId);
}

void ItemUseOutOfBattle_Bike(u8 taskId)
{
    s16* data = gTasks[taskId].data;
    s16 coordsY;
    s16 coordsX;
    u8 behavior;
    PlayerGetDestCoords(&coordsX, &coordsY);
    behavior = MapGridGetMetatileBehaviorAt(coordsX, coordsY);
    if (FlagGet(FLAG_SYS_CYCLING_ROAD) == TRUE || MetatileBehavior_IsVerticalRail(behavior) == TRUE || MetatileBehavior_IsHorizontalRail(behavior) == TRUE || MetatileBehavior_IsIsolatedVerticalRail(behavior) == TRUE || MetatileBehavior_IsIsolatedHorizontalRail(behavior) == TRUE)
        DisplayCannotDismountBikeMessage(taskId, tUsingRegisteredKeyItem);
    else
    {
        if (Overworld_IsBikingAllowed() == TRUE && IsBikingDisallowedByPlayer() == 0)
        {
            sItemUseOnFieldCB = ItemUseOnFieldCB_Bike;
            SetUpItemUseOnFieldCallback(taskId);
        }
        else
            DisplayDadsAdviceCannotUseItemMessage(taskId, tUsingRegisteredKeyItem);
    }
}

static void ItemUseOnFieldCB_Bike(u8 taskId)
{
    if (!ItemId_GetSecondaryId(gSpecialVar_ItemId))
        GetOnOffBike(PLAYER_AVATAR_FLAG_MACH_BIKE);
    else
        GetOnOffBike(PLAYER_AVATAR_FLAG_ACRO_BIKE);
    POF_FollowMe_HandleBike(); //tx_pokemon_follower
    ScriptUnfreezeObjectEvents();
    ScriptContext2_Disable();
    DestroyTask(taskId);
}

static bool32 CanFish(void)
{
    s16 x, y;
    u16 tileBehavior;

    GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
    tileBehavior = MapGridGetMetatileBehaviorAt(x, y);

    if (MetatileBehavior_IsWaterfall(tileBehavior))
        return FALSE;

    if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_UNDERWATER))
        return FALSE;

    if (!TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING))
    {
        if (IsPlayerFacingSurfableFishableWater())
            return TRUE;
    }
    else
    {
        if (MetatileBehavior_IsSurfableWaterOrUnderwater(tileBehavior) && !MapGridIsImpassableAt(x, y))
            return TRUE;
        if (MetatileBehavior_8089510(tileBehavior) == TRUE)
            return TRUE;
    }

    return FALSE;
}

void ItemUseOutOfBattle_Rod(u8 taskId)
{
    if (CanFish() == TRUE)
    {
        sItemUseOnFieldCB = ItemUseOnFieldCB_Rod;
        SetUpItemUseOnFieldCallback(taskId);
    }
    else
        DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem);
}

static void ItemUseOnFieldCB_Rod(u8 taskId)
{
    StartFishing(ItemId_GetSecondaryId(gSpecialVar_ItemId));
    DestroyTask(taskId);
}

void ItemUseOutOfBattle_Itemfinder(u8 var)
{
    IncrementGameStat(GAME_STAT_USED_ITEMFINDER);
    sItemUseOnFieldCB = ItemUseOnFieldCB_Itemfinder;
    SetUpItemUseOnFieldCallback(var);
}

static void ItemUseOnFieldCB_Itemfinder(u8 taskId)
{
    if (ItemfinderCheckForHiddenItems(gMapHeader.events, taskId) == TRUE)
        gTasks[taskId].func = Task_UseItemfinder;
    else
        DisplayItemMessageOnField(taskId, gText_ItemFinderNothing, Task_CloseItemfinderMessage);
}

// Define itemfinder task data
#define tItemDistanceX    data[0]
#define tItemDistanceY    data[1]
#define tItemFound        data[2]
#define tCounter          data[3] // Used to count delay between beeps and rotations during player spin
#define tItemfinderBeeps  data[4]
#define tFacingDir        data[5]

static void Task_UseItemfinder(u8 taskId)
{
    u8 playerDir;
    u8 playerDirToItem;
    u8 i;
    s16* data = gTasks[taskId].data;
    if (tCounter == 0)
    {
        if (tItemfinderBeeps == 4)
        {
            playerDirToItem = GetDirectionToHiddenItem(tItemDistanceX, tItemDistanceY);
            if (playerDirToItem != DIR_NONE)
            {
                PlayerFaceHiddenItem(sClockwiseDirections[playerDirToItem - 1]);
                gTasks[taskId].func = Task_HiddenItemNearby;
            }
            else
            {
                // Player is standing on hidden item
                playerDir = GetPlayerFacingDirection();
                for (i = 0; i < ARRAY_COUNT(sClockwiseDirections); i++)
                {
                    if (playerDir == sClockwiseDirections[i])
                        tFacingDir = (i + 1) & 3;
                }
                gTasks[taskId].func = Task_StandingOnHiddenItem;
                tCounter = 0;
                tItemFound = 0;
            }
            return;
        }
        PlaySE(SE_ITEMFINDER);
        tItemfinderBeeps++;
    }
    tCounter = (tCounter + 1) & 0x1F;
}

static void Task_CloseItemfinderMessage(u8 taskId)
{
    ClearDialogWindowAndFrame(0, 1);
    ScriptUnfreezeObjectEvents();
    ScriptContext2_Disable();
    DestroyTask(taskId);
}

static bool8 ItemfinderCheckForHiddenItems(const struct MapEvents *events, u8 taskId)
{
    int itemX, itemY;
    s16 playerX, playerY, i, distanceX, distanceY;
    PlayerGetDestCoords(&playerX, &playerY);
    gTasks[taskId].tItemFound = FALSE;

    for (i = 0; i < events->bgEventCount; i++)
    {
        // Check if there are any hidden items on the current map that haven't been picked up
        if (events->bgEvents[i].kind == BG_EVENT_HIDDEN_ITEM && !FlagGet(events->bgEvents[i].bgUnion.hiddenItem.hiddenItemId + FLAG_HIDDEN_ITEMS_START))
        {
            itemX = (u16)events->bgEvents[i].x + 7;
            distanceX = itemX - playerX;
            itemY = (u16)events->bgEvents[i].y + 7;
            distanceY = itemY - playerY;

            if ((u16)(distanceX + 7) < 15 && (distanceY >= -5) && (distanceY < 6))
                SetDistanceOfClosestHiddenItem(taskId, distanceX, distanceY);
        }
    }

    CheckForHiddenItemsInMapConnection(taskId);
    if (gTasks[taskId].tItemFound == TRUE)
        return TRUE;
    else
        return FALSE;
}

static bool8 IsHiddenItemPresentAtCoords(const struct MapEvents *events, s16 x, s16 y)
{
    u8 bgEventCount = events->bgEventCount;
    struct BgEvent *bgEvent = events->bgEvents;
    int i;

    for (i = 0; i < bgEventCount; i++)
    {
        if (bgEvent[i].kind == BG_EVENT_HIDDEN_ITEM && x == (u16)bgEvent[i].x && y == (u16)bgEvent[i].y) // hidden item and coordinates matches x and y passed?
        {
            if (!FlagGet(bgEvent[i].bgUnion.hiddenItem.hiddenItemId + FLAG_HIDDEN_ITEMS_START))
                return TRUE;
            else
                return FALSE;
        }
    }
    return FALSE;
}

static bool8 IsHiddenItemPresentInConnection(struct MapConnection *connection, int x, int y)
{

    u16 localX, localY;
    u32 localOffset;
    s32 localLength;

    struct MapHeader const *const mapHeader = GetMapHeaderFromConnection(connection);

    switch (connection->direction)
    {
    // same weird temp variable behavior seen in IsHiddenItemPresentAtCoords
    case 2:
        localOffset = connection->offset + 7;
        localX = x - localOffset;
        localLength = mapHeader->mapLayout->height - 7;
        localY = localLength + y; // additions are reversed for some reason
        break;
    case 1:
        localOffset = connection->offset + 7;
        localX = x - localOffset;
        localLength = gMapHeader.mapLayout->height + 7;
        localY = y - localLength;
        break;
    case 3:
        localLength = mapHeader->mapLayout->width - 7;
        localX = localLength + x; // additions are reversed for some reason
        localOffset = connection->offset + 7;
        localY = y - localOffset;
        break;
    case 4:
        localLength = gMapHeader.mapLayout->width + 7;
        localX = x - localLength;
        localOffset = connection->offset + 7;
        localY = y - localOffset;
        break;
    default:
        return FALSE;
    }
    return IsHiddenItemPresentAtCoords(mapHeader->events, localX, localY);
}

static void CheckForHiddenItemsInMapConnection(u8 taskId)
{
    s16 playerX, playerY;
    s16 x, y;
    s16 width = gMapHeader.mapLayout->width + 7;
    s16 height = gMapHeader.mapLayout->height + 7;

    s16 var1 = 7;
    s16 var2 = 7;

    PlayerGetDestCoords(&playerX, &playerY);

    for (x = playerX - 7; x <= playerX + 7; x++)
    {
        for (y = playerY - 5; y <= playerY + 5; y++)
        {
            if (var1 > x
             || x >= width
             || var2 > y
             || y >= height)
            {
                struct MapConnection *conn = GetConnectionAtCoords(x, y);
                if (conn && IsHiddenItemPresentInConnection(conn, x, y) == TRUE)
                    SetDistanceOfClosestHiddenItem(taskId, x - playerX, y - playerY);
            }
        }
    }
}

static void SetDistanceOfClosestHiddenItem(u8 taskId, s16 itemDistanceX, s16 itemDistanceY)
{
    s16 *data = gTasks[taskId].data;
    s16 oldItemAbsX, oldItemAbsY, newItemAbsX, newItemAbsY;

    if (tItemFound == FALSE)
    {
        // No other items found yet, set this one
        tItemDistanceX = itemDistanceX;
        tItemDistanceY = itemDistanceY;
        tItemFound = TRUE;
    }
    else
    {
        // Other items have been found, check if this one is closer

        // Get absolute x distance of the already-found item
        if (tItemDistanceX < 0)
            oldItemAbsX = tItemDistanceX * -1; // WEST
        else
            oldItemAbsX = tItemDistanceX;      // EAST

        // Get absolute y distance of the already-found item
        if (tItemDistanceY < 0)
            oldItemAbsY = tItemDistanceY * -1; // NORTH
        else
            oldItemAbsY = tItemDistanceY;      // SOUTH

        // Get absolute x distance of the newly-found item
        if (itemDistanceX < 0)
            newItemAbsX = itemDistanceX * -1;
        else
            newItemAbsX = itemDistanceX;

        // Get absolute y distance of the newly-found item
        if (itemDistanceY < 0)
            newItemAbsY = itemDistanceY * -1;
        else
            newItemAbsY = itemDistanceY;


        if (oldItemAbsX + oldItemAbsY > newItemAbsX + newItemAbsY)
        {
            // New item is closer
            tItemDistanceX = itemDistanceX;
            tItemDistanceY = itemDistanceY;
        }
        else
        {
            if (oldItemAbsX + oldItemAbsY == newItemAbsX + newItemAbsY
            && (oldItemAbsY > newItemAbsY || (oldItemAbsY == newItemAbsY && tItemDistanceY < itemDistanceY)))
            {
                // If items are equal distance, use whichever is closer on the Y axis or further south
                tItemDistanceX = itemDistanceX;
                tItemDistanceY = itemDistanceY;
            }
        }
    }
}

static u8 GetDirectionToHiddenItem(s16 itemDistanceX, s16 itemDistanceY)
{
    s16 absX, absY;

    if (itemDistanceX == 0 && itemDistanceY == 0)
        return DIR_NONE; // player is standing on the item.

    // Get absolute X distance.
    if (itemDistanceX < 0)
        absX = itemDistanceX * -1;
    else
        absX = itemDistanceX;

    // Get absolute Y distance.
    if (itemDistanceY < 0)
        absY = itemDistanceY * -1;
    else
        absY = itemDistanceY;

    if (absX > absY)
    {
        if (itemDistanceX < 0)
            return DIR_EAST;
        else
            return DIR_NORTH;
    }
    else
    {
        if (absX < absY)
        {
            if (itemDistanceY < 0)
                return DIR_SOUTH;
            else
                return DIR_WEST;
        }
        if (absX == absY)
        {
            if (itemDistanceY < 0)
                return DIR_SOUTH;
            else
                return DIR_WEST;
        }
        return DIR_NONE; // Unreachable
    }
}

static void PlayerFaceHiddenItem(u8 direction)
{
    ObjectEventClearHeldMovementIfFinished(&gObjectEvents[GetObjectEventIdByLocalIdAndMap(OBJ_EVENT_ID_PLAYER, 0, 0)]);
    ObjectEventClearHeldMovement(&gObjectEvents[GetObjectEventIdByLocalIdAndMap(OBJ_EVENT_ID_PLAYER, 0, 0)]);
    UnfreezeObjectEvent(&gObjectEvents[GetObjectEventIdByLocalIdAndMap(OBJ_EVENT_ID_PLAYER, 0, 0)]);
    PlayerTurnInPlace(direction);
}

static void Task_HiddenItemNearby(u8 taskId)
{
    if (ObjectEventCheckHeldMovementStatus(&gObjectEvents[GetObjectEventIdByLocalIdAndMap(OBJ_EVENT_ID_PLAYER, 0, 0)]) == TRUE)
        DisplayItemMessageOnField(taskId, gText_ItemFinderNearby, Task_CloseItemfinderMessage);
}

static void Task_StandingOnHiddenItem(u8 taskId)
{
    s16 *data = gTasks[taskId].data;

    if (ObjectEventCheckHeldMovementStatus(&gObjectEvents[GetObjectEventIdByLocalIdAndMap(OBJ_EVENT_ID_PLAYER, 0, 0)]) == TRUE
    || tItemFound == FALSE)
    {
        // Spin player around on item
        PlayerFaceHiddenItem(sClockwiseDirections[tFacingDir]);
        tItemFound = TRUE;
        tFacingDir = (tFacingDir + 1) & 3;
        tCounter++;

        if (tCounter == 4)
            DisplayItemMessageOnField(taskId, gText_ItemFinderOnTop, Task_CloseItemfinderMessage);
    }
}

// Undefine itemfinder task data
#undef tItemDistanceX
#undef tItemDistanceY
#undef tItemFound
#undef tCounter
#undef tItemfinderBeeps
#undef tFacingDir

void ItemUseOutOfBattle_PokeblockCase(u8 taskId)
{
    if (MenuHelpers_LinkSomething() == TRUE) // link func
    {
        DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem);
    }
    else if (gTasks[taskId].tUsingRegisteredKeyItem != TRUE)
    {
        gBagMenu->exitCallback = CB2_OpenPokeblockCaseOnField;
        Task_FadeAndCloseBagMenu(taskId);
    }
    else
    {
        gFieldCallback = sub_80AF6D4;
        FadeScreen(FADE_TO_BLACK, 0);
        gTasks[taskId].func = sub_80FDC00;
    }
}

static void CB2_OpenPokeblockCaseOnField(void)
{
    OpenPokeblockCase(PBLOCK_CASE_FIELD, CB2_ReturnToBagMenuPocket);
}

static void sub_80FDC00(u8 taskId)
{
    if (!gPaletteFade.active)
    {
        CleanupOverworldWindowsAndTilemaps();
        OpenPokeblockCase(PBLOCK_CASE_FIELD, CB2_ReturnToField);
        DestroyTask(taskId);
    }
}

void ItemUseOutOfBattle_CoinCase(u8 taskId)
{
    ConvertIntToDecimalStringN(gStringVar1, GetCoins(), STR_CONV_MODE_LEFT_ALIGN, 4);
    StringExpandPlaceholders(gStringVar4, gText_CoinCase);

    if (!gTasks[taskId].tUsingRegisteredKeyItem)
    {
        DisplayItemMessage(taskId, 1, gStringVar4, BagMenu_InitListsMenu);
    }
    else
    {
        DisplayItemMessageOnField(taskId, gStringVar4, Task_CloseCantUseKeyItemMessage);
    }
}

void ItemUseOutOfBattle_PowderJar(u8 taskId)
{
    ConvertIntToDecimalStringN(gStringVar1, GetBerryPowder(), STR_CONV_MODE_LEFT_ALIGN, 5);
    StringExpandPlaceholders(gStringVar4, gText_PowderQty);

    if (!gTasks[taskId].tUsingRegisteredKeyItem)
    {
        DisplayItemMessage(taskId, 1, gStringVar4, BagMenu_InitListsMenu);
    }
    else
    {
        DisplayItemMessageOnField(taskId, gStringVar4, Task_CloseCantUseKeyItemMessage);
    }
}

void ItemUseOutOfBattle_Berry(u8 taskId)
{
    if (IsPlayerFacingEmptyBerryTreePatch() == TRUE)
    {
        sItemUseOnFieldCB = ItemUseOnFieldCB_Berry;
        gFieldCallback = FieldCB_UseItemOnField;
        gBagMenu->exitCallback = CB2_ReturnToField;
        Task_FadeAndCloseBagMenu(taskId);
    }
    else
    {
        ItemId_GetFieldFunc(gSpecialVar_ItemId)(taskId);
    }
}

static void ItemUseOnFieldCB_Berry(u8 taskId)
{
    RemoveBagItem(gSpecialVar_ItemId, 1);
    ScriptContext2_Enable();
    ScriptContext1_SetupScript(BerryTree_EventScript_ItemUsePlantBerry);
    DestroyTask(taskId);
}

void ItemUseOutOfBattle_WailmerPail(u8 taskId)
{
    if (TryToWaterSudowoodo() == TRUE)
    {
        sItemUseOnFieldCB = ItemUseOnFieldCB_WailmerPailSudowoodo;
        SetUpItemUseOnFieldCallback(taskId);
    }
    else if (TryToWaterBerryTree() == TRUE)
    {
        sItemUseOnFieldCB = ItemUseOnFieldCB_WailmerPailBerry;
        SetUpItemUseOnFieldCallback(taskId);
    }
    else
    {
        DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem);
    }
}

static void ItemUseOnFieldCB_WailmerPailBerry(u8 taskId)
{
    ScriptContext2_Enable();
    ScriptContext1_SetupScript(BerryTree_EventScript_ItemUseWailmerPail);
    DestroyTask(taskId);
}

static bool8 TryToWaterSudowoodo(void)
{
    s16 x, y;
    u8 z;
    u8 objId;
    GetXYCoordsOneStepInFrontOfPlayer(&x, &y);
    z = PlayerGetZCoord();
    objId = GetObjectEventIdByXYZ(x, y, z);
    if (objId == OBJECT_EVENTS_COUNT || gObjectEvents[objId].graphicsId != OBJ_EVENT_GFX_SUDOWOODO)
        return FALSE;
    else
        return TRUE;
}

static void ItemUseOnFieldCB_WailmerPailSudowoodo(u8 taskId)
{
    ScriptContext2_Enable();
    ScriptContext1_SetupScript(BattleFrontier_OutsideEast_EventScript_WaterSudowoodo);
    DestroyTask(taskId);
}

void ItemUseOutOfBattle_Medicine(u8 taskId)
{
    gItemUseCB = ItemUseCB_Medicine;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_UpAndWings(u8 taskId)
{
    gItemUseCB = ItemUseCB_UpAndWings;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_AbilityCapsule(u8 taskId)
{
    gItemUseCB = ItemUseCB_AbilityCapsule;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_AbilityPatch(u8 taskId)
{
    gItemUseCB = ItemUseCB_AbilityPatch;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_ReduceEV(u8 taskId)
{
    gItemUseCB = ItemUseCB_ReduceEV;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_SacredAsh(u8 taskId)
{
    gItemUseCB = ItemUseCB_SacredAsh;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_PPRecovery(u8 taskId)
{
    gItemUseCB = ItemUseCB_PPRecovery;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_PPUp(u8 taskId)
{
    gItemUseCB = ItemUseCB_PPUp;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_RareCandy(u8 taskId)
{
    gItemUseCB = ItemUseCB_RareCandy;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_TMHM(u8 taskId)
{
    if (gSpecialVar_ItemId >= ITEM_HM01_CUT)
        DisplayItemMessage(taskId, 1, gText_BootedUpHM, BootUpSoundTMHM); // HM
    else
        DisplayItemMessage(taskId, 1, gText_BootedUpTM, BootUpSoundTMHM); // TM
}

static void BootUpSoundTMHM(u8 taskId)
{
    PlaySE(SE_PC_LOGIN);
    gTasks[taskId].func = Task_ShowTMHMContainedMessage;
}

static void Task_ShowTMHMContainedMessage(u8 taskId)
{
    if (JOY_NEW(A_BUTTON | B_BUTTON))
    {
        StringCopy(gStringVar1, gMoveNames[ItemIdToBattleMoveId(gSpecialVar_ItemId)]);
        StringExpandPlaceholders(gStringVar4, gText_TMHMContainedVar1);
        DisplayItemMessage(taskId, 1, gStringVar4, UseTMHMYesNo);
    }
}

static void UseTMHMYesNo(u8 taskId)
{
    BagMenu_YesNo(taskId, 6, &sUseTMHMYesNoFuncTable);
}

static void UseTMHM(u8 taskId)
{
    gItemUseCB = ItemUseCB_TMHM;
    SetUpItemUseCallback(taskId);
}

static void RemoveUsedItem(void)
{
    RemoveBagItem(gSpecialVar_ItemId, 1);
    CopyItemName(gSpecialVar_ItemId, gStringVar2);
    StringExpandPlaceholders(gStringVar4, gText_PlayerUsedVar2);
    if (!InBattlePyramid())
    {
        //bug fix:离洞绳
//        UpdatePocketItemList(ItemId_GetPocket(gSpecialVar_ItemId));
//        SetInitialScrollAndCursorPositions(ItemId_GetPocket(gSpecialVar_ItemId));
    }
    else
    {
        sub_81C5924();
        sub_81C59BC();
    }
}

void ItemUseOutOfBattle_Repel(u8 taskId)
{
    if (VarGet(VAR_LURE_STEP_COUNT) == 0)
    {
        if (VarGet(VAR_REPEL_STEP_COUNT) == 0)
            gTasks[taskId].func = Task_StartUseRepel;
        else if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, gText_RepelEffectsLingered, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, gText_RepelEffectsLingered, Task_CloseBattlePyramidBagMessage);
    }
    else
    {
        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, gText_LureEffectsLingered, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, gText_LureEffectsLingered, Task_CloseBattlePyramidBagMessage);
    }
}

static void Task_StartUseRepel(u8 taskId)
{
    s16* data = gTasks[taskId].data;

    if (++data[8] > 7)
    {
        data[8] = 0;
        PlaySE(SE_REPEL);
        gTasks[taskId].func = Task_UseRepel;
    }
}

static void Task_UseRepel(u8 taskId)
{
    if (!IsSEPlaying())
    {
        VarSet(VAR_REPEL_STEP_COUNT, ItemId_GetHoldEffectParam(gSpecialVar_ItemId));
        VarSet(VAR_LAST_REPEL, gSpecialVar_ItemId);
        RemoveUsedItem();
        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, gStringVar4, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, gStringVar4, Task_CloseBattlePyramidBagMessage);
    }
}

static void Task_UseLure(u8 taskId)
{
    if (!IsSEPlaying())
    {
        VarSet(VAR_LURE_STEP_COUNT, ItemId_GetHoldEffectParam(gSpecialVar_ItemId));
        VarSet(VAR_LAST_LURE, gSpecialVar_ItemId);
        RemoveUsedItem();
        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, gStringVar4, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, gStringVar4, Task_CloseBattlePyramidBagMessage);
    }
}

static void Task_StartUseLure(u8 taskId)
{
    s16* data = gTasks[taskId].data;

    if (++data[8] > 7)
    {
        data[8] = 0;
        PlaySE(SE_REPEL);
        gTasks[taskId].func = Task_UseLure;
    }
}

void ItemUseOutOfBattle_Lure(u8 taskId)
{
    if (VarGet(VAR_REPEL_STEP_COUNT) == 0)
    {
        if (VarGet(VAR_LURE_STEP_COUNT) == 0)
            gTasks[taskId].func = Task_StartUseLure;
        else if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, gText_LureEffectsLingered, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, gText_LureEffectsLingered, Task_CloseBattlePyramidBagMessage);
    }
    else
    {
        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, gText_RepelEffectsLingered, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, gText_RepelEffectsLingered, Task_CloseBattlePyramidBagMessage);
    }
}

static void Task_UsedBlackWhiteFlute(u8 taskId)
{
    if(++gTasks[taskId].data[8] > 7)
    {
        PlaySE(SE_GLASS_FLUTE);
        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, gStringVar4, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, gStringVar4, Task_CloseBattlePyramidBagMessage);
    }
}

void ItemUseOutOfBattle_BlackWhiteFlute(u8 taskId)
{
    CopyItemName(gSpecialVar_ItemId, gStringVar2);
    if (gSpecialVar_ItemId == ITEM_WHITE_FLUTE)
    {
        FlagSet(FLAG_SYS_ENC_UP_ITEM);
        FlagClear(FLAG_SYS_ENC_DOWN_ITEM);
        StringExpandPlaceholders(gStringVar4, gText_UsedVar2WildLured);
    }
    else
    {
        FlagSet(FLAG_SYS_ENC_DOWN_ITEM);
        FlagClear(FLAG_SYS_ENC_UP_ITEM);
        StringExpandPlaceholders(gStringVar4, gText_UsedVar2WildRepelled);
    }
    gTasks[taskId].data[8] = 0;
    gTasks[taskId].func = Task_UsedBlackWhiteFlute;
}

void Task_UseDigEscapeRopeOnField(u8 taskId)
{
    ResetInitialPlayerAvatarState();
    StartEscapeRopeFieldEffect();
    DestroyTask(taskId);
}

static void ItemUseOnFieldCB_EscapeRope(u8 taskId)
{
    Overworld_ResetStateAfterDigEscRope();
    RemoveUsedItem();
    gTasks[taskId].data[0] = 0;
    DisplayItemMessageOnField(taskId, gStringVar4, Task_UseDigEscapeRopeOnField);
}

bool8 CanUseDigOrEscapeRopeOnCurMap(void)
{
    if (gMapHeader.flags & MAP_ALLOW_ESCAPING)
        return TRUE;
    else
        return FALSE;
}

void ItemUseOutOfBattle_EscapeRope(u8 taskId)
{
    if (CanUseDigOrEscapeRopeOnCurMap() == TRUE)
    {
        sItemUseOnFieldCB = ItemUseOnFieldCB_EscapeRope;
        SetUpItemUseOnFieldCallback(taskId);
    }
    else
    {
        DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem);
    }
}

void ItemUseOutOfBattle_EvolutionStone(u8 taskId)
{
    gItemUseCB = ItemUseCB_EvolutionStone;
    SetUpItemUseCallback(taskId);
}

static bool8 NuzlockeGetWBFlag(u16 mapLayOutId)
{
    u8 slot = mapLayOutId / 8;
    u8 mod  = mapLayOutId % 8;

    return gSaveBlock1Ptr->NuzlockeWBFlags[slot] & (1 << mod);
}

void ItemUseInBattle_PokeBall(u8 taskId)
{
    if (FlagGet(FLAG_TEAM_ROCKET_MODE))
    {
        static const u8 textCantThrowPokeBall[] = _("作为一名火箭队，\n你只应该抢别人的精灵！\p");

        DisplayItemMessage(taskId, 1, textCantThrowPokeBall, BagMenu_InitListsMenu);
    }
    else if (FlagGet(FLAG_NUZLOCKE_MODE) && NuzlockeGetWBFlag(gMapHeader.mapLayoutId))
    {
        static const u8 textCantThrowPokeBall[] = _("由于Nuzlocke规则限制\n您无法使用精灵球！\p");

        DisplayItemMessage(taskId, 1, textCantThrowPokeBall, BagMenu_InitListsMenu);
    }
    else if (IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT))
        && IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT))) // There are two present pokemon.
    {
        static const u8 textCantThrowPokeBall[] = _("现在不能丢球！\n那里有两只宝可梦！\p");

        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, textCantThrowPokeBall, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, textCantThrowPokeBall, Task_CloseBattlePyramidBagMessage);
    }
    else if (gBattlerInMenuId == GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT)
             && IsBattlerAlive(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT))) // Attempting to throw a ball with the second pokemon while both are alive.
    {
        static const u8 textCantThrowPokeBall[] = _("不能丢球！\p");

        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, textCantThrowPokeBall, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, textCantThrowPokeBall, Task_CloseBattlePyramidBagMessage);
    }
    else if (IsPlayerPartyAndPokemonStorageFull() == FALSE) // have room for mon?
    {
        RemoveBagItem(gSpecialVar_ItemId, 1);
        if (!InBattlePyramid())
            Task_FadeAndCloseBagMenu(taskId);
        else
            CloseBattlePyramidBagAndSetCallback(taskId);
    }
    else
    {
        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, gText_BoxFull, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, gText_BoxFull, Task_CloseBattlePyramidBagMessage);
    }
}

static void Task_CloseStatIncreaseMessage(u8 taskId)
{
    if (JOY_NEW(A_BUTTON | B_BUTTON))
    {
        if (!InBattlePyramid())
            Task_FadeAndCloseBagMenu(taskId);
        else
            CloseBattlePyramidBagAndSetCallback(taskId);
    }
}

static void Task_UseStatIncreaseItem(u8 taskId)
{
    if(++gTasks[taskId].data[8] > 7)
    {
        PlaySE(SE_USE_ITEM);
        RemoveBagItem(gSpecialVar_ItemId, 1);
        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, UseStatIncreaseItem(gSpecialVar_ItemId), Task_CloseStatIncreaseMessage);
        else
            DisplayItemMessageInBattlePyramid(taskId, UseStatIncreaseItem(gSpecialVar_ItemId), Task_CloseStatIncreaseMessage);
    }
}

// e.g. X Attack, Guard Spec
void ItemUseInBattle_StatIncrease(u8 taskId)
{
    u16 partyId = gBattlerPartyIndexes[gBattlerInMenuId];

    if (ExecuteTableBasedItemEffect(&gPlayerParty[partyId], gSpecialVar_ItemId, partyId, 0) != FALSE)
    {
        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, gText_WontHaveEffect, BagMenu_InitListsMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, gText_WontHaveEffect, Task_CloseBattlePyramidBagMessage);
    }
    else
    {
        gTasks[taskId].func = Task_UseStatIncreaseItem;
        gTasks[taskId].data[8] = 0;
    }
}

static void ItemUseInBattle_ShowPartyMenu(u8 taskId)
{
    if (!InBattlePyramid())
    {
        gBagMenu->exitCallback = ChooseMonForInBattleItem;
        Task_FadeAndCloseBagMenu(taskId);
    }
    else
    {
        gPyramidBagResources->callback2 = ChooseMonForInBattleItem;
        CloseBattlePyramidBagAndSetCallback(taskId);
    }
}

void ItemUseInBattle_Medicine(u8 taskId)
{
    gItemUseCB = ItemUseCB_Medicine;
    ItemUseInBattle_ShowPartyMenu(taskId);
}

// Unused. Sacred Ash cannot be used in battle
void ItemUseInBattle_SacredAsh(u8 taskId)
{
    gItemUseCB = ItemUseCB_SacredAsh;
    ItemUseInBattle_ShowPartyMenu(taskId);
}

void ItemUseInBattle_PPRecovery(u8 taskId)
{
    gItemUseCB = ItemUseCB_PPRecovery;
    ItemUseInBattle_ShowPartyMenu(taskId);
}

// Fluffy Tail / Poke Doll
void ItemUseInBattle_Escape(u8 taskId)
{

    if((gBattleTypeFlags & BATTLE_TYPE_TRAINER) == FALSE)
    {
        RemoveUsedItem();
        if (!InBattlePyramid())
            DisplayItemMessage(taskId, 1, gStringVar4, Task_FadeAndCloseBagMenu);
        else
            DisplayItemMessageInBattlePyramid(taskId, gStringVar4, CloseBattlePyramidBagAndSetCallback);
    }
    else
    {
        DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem);
    }
}

void ItemUseOutOfBattle_EnigmaBerry(u8 taskId)
{
    switch (GetItemEffectType(gSpecialVar_ItemId))
    {
    case ITEM_EFFECT_HEAL_HP:
    case ITEM_EFFECT_CURE_POISON:
    case ITEM_EFFECT_CURE_SLEEP:
    case ITEM_EFFECT_CURE_BURN:
    case ITEM_EFFECT_CURE_FREEZE:
    case ITEM_EFFECT_CURE_PARALYSIS:
    case ITEM_EFFECT_CURE_ALL_STATUS:
    case ITEM_EFFECT_ATK_EV:
    case ITEM_EFFECT_HP_EV:
    case ITEM_EFFECT_SPATK_EV:
    case ITEM_EFFECT_SPDEF_EV:
    case ITEM_EFFECT_SPEED_EV:
    case ITEM_EFFECT_DEF_EV:
        gTasks[taskId].data[4] = 1;
        ItemUseOutOfBattle_Medicine(taskId);
        break;
    case ITEM_EFFECT_SACRED_ASH:
        gTasks[taskId].data[4] = 1;
        ItemUseOutOfBattle_SacredAsh(taskId);
        break;
    case ITEM_EFFECT_RAISE_LEVEL:
        gTasks[taskId].data[4] = 1;
        ItemUseOutOfBattle_RareCandy(taskId);
        break;
    case ITEM_EFFECT_PP_UP:
    case ITEM_EFFECT_PP_MAX:
        gTasks[taskId].data[4] = 1;
        ItemUseOutOfBattle_PPUp(taskId);
        break;
    case ITEM_EFFECT_HEAL_PP:
        gTasks[taskId].data[4] = 1;
        ItemUseOutOfBattle_PPRecovery(taskId);
        break;
    default:
        gTasks[taskId].data[4] = 4;
        ItemUseOutOfBattle_CannotUse(taskId);
        break;
    }
}

void ItemUseInBattle_EnigmaBerry(u8 taskId)
{
    switch (GetItemEffectType(gSpecialVar_ItemId))
    {
    case ITEM_EFFECT_X_ITEM:
        ItemUseInBattle_StatIncrease(taskId);
        break;
    case ITEM_EFFECT_HEAL_HP:
    case ITEM_EFFECT_CURE_POISON:
    case ITEM_EFFECT_CURE_SLEEP:
    case ITEM_EFFECT_CURE_BURN:
    case ITEM_EFFECT_CURE_FREEZE:
    case ITEM_EFFECT_CURE_PARALYSIS:
    case ITEM_EFFECT_CURE_ALL_STATUS:
    case ITEM_EFFECT_CURE_CONFUSION:
    case ITEM_EFFECT_CURE_INFATUATION:
        ItemUseInBattle_Medicine(taskId);
        break;
    case ITEM_EFFECT_HEAL_PP:
        ItemUseInBattle_PPRecovery(taskId);
        break;
    default:
        ItemUseOutOfBattle_CannotUse(taskId);
        break;
    }
}

void ItemUseOutOfBattle_FormChange(u8 taskId) 
{
    gItemUseCB = ItemUseCB_FormChange;
    gTasks[taskId].data[0] = FALSE;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_FormChange_ConsumedOnUse(u8 taskId)
{
    gItemUseCB = ItemUseCB_FormChange_ConsumedOnUse;
    gTasks[taskId].data[0] = TRUE;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_CannotUse(u8 taskId)
{
    DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem);
}

#define CURSORID data[0]
#define STEP data[1]
#define SELECTION data[2]
#define COUNT data[3]
#define TYPE data[3]

static const struct WindowTemplate sPhoneWinTemplates[] =
{
    {
        .bg = 0,
        .tilemapLeft = 1,
        .tilemapTop = 1,
        .width = 0x1C,
        .height = 0xF,
        .paletteNum = 8,
        .baseBlock = 0x57
    },
    {
        .bg = 0,
        .tilemapLeft = 1,
        .tilemapTop = 0x11,
        .width = 0x1C,
        .height = 2,
        .paletteNum = 8,
        .baseBlock = 0
    },
    {
        0xFF,
        0,
        0,
        0,
        0,
        0,
        0
    }
};

static const struct BgTemplate sPhoneBgTemplates[] =
{
   {
       .bg = 0,
       .charBaseIndex = 0,
       .mapBaseIndex = 31,
       .screenSize = 0,
       .paletteMode = 0,
       .priority = 2,
       .baseTile = 1
   },
   {
       .bg = 1,
       .charBaseIndex = 1,
       .mapBaseIndex = 29,
       .screenSize = 1,
       .paletteMode = 0,
       .priority = 3,
       .baseTile = 0
   }
};

const struct OamData oamcursor =
{
    .y = 0,
    .affineMode = 0,
    .objMode = 0,
    .mosaic = 0,
    .bpp = 0, //16色
    .shape = 0, //方形
    .x = 0,
    .matrixNum = 0,
    .size = 1, //16*16
    .tileNum = 0,
    .priority = 0,
    .paletteNum = 0,
    .affineParam = 0
};

const union AnimCmd anim[] =
{
    ANIMCMD_FRAME(0, 0),
    ANIMCMD_END
};

const union AnimCmd *const animtable[] =
{
    anim
};

const struct SpriteTemplate CursorTemplate = //使用sheet
{
    .tileTag = 0x1300,
    .paletteTag = 0x1300,
    .oam = &oamcursor,
    .anims = animtable,
    .images = NULL,
    .affineAnims = gDummySpriteAffineAnimTable,
    .callback = SpriteCallbackDummy
};

const static u8 color[] = {0, 2, 3};
const u16 PMPosX[6] = {0x25, 0x45, 0x65, 0x85, 0xA5, 0xC5};

EWRAM_DATA static const u16* gItemTable = NULL;
EWRAM_DATA static u8 gItemTableCounts = 0;

const static u16 sItemTable0[] = {ITEM_POKE_BALL, ITEM_POTION, ITEM_ANTIDOTE, ITEM_BURN_HEAL, ITEM_ICE_HEAL, ITEM_AWAKENING, ITEM_PARALYZE_HEAL};

const static u16 sItemTable1[] = {ITEM_POKE_BALL, ITEM_GREAT_BALL, ITEM_ULTRA_BALL, ITEM_POTION, ITEM_ANTIDOTE, ITEM_BURN_HEAL, ITEM_ICE_HEAL, ITEM_AWAKENING,
								  ITEM_PARALYZE_HEAL, ITEM_FULL_RESTORE, ITEM_MAX_POTION, ITEM_HYPER_POTION, ITEM_SUPER_POTION, ITEM_FULL_HEAL};

const static u16 sItemTable2[] = {ITEM_POKE_BALL, ITEM_GREAT_BALL, ITEM_ULTRA_BALL, ITEM_POTION, ITEM_ANTIDOTE, ITEM_BURN_HEAL, ITEM_ICE_HEAL, ITEM_AWAKENING,
								  ITEM_PARALYZE_HEAL, ITEM_FULL_RESTORE, ITEM_MAX_POTION, ITEM_HYPER_POTION, ITEM_SUPER_POTION, ITEM_FULL_HEAL, ITEM_REVIVE,
								  ITEM_MAX_REVIVE, ITEM_ENERGY_POWDER, ITEM_ENERGY_ROOT, ITEM_HEAL_POWDER, ITEM_REVIVAL_HERB, ITEM_ETHER, ITEM_MAX_ETHER, ITEM_ELIXIR,
								  ITEM_MAX_ELIXIR, ITEM_LAVA_COOKIE};

static void LoadgItemTable(void)
{
    if (FlagGet(FLAG_ONLINE_BUY_2))
	{
        gItemTable = sItemTable2;
		gItemTableCounts = ARRAY_COUNT(sItemTable2);
    }
	else if (FlagGet(FLAG_ONLINE_BUY_1))
	{
		gItemTable = sItemTable1;
		gItemTableCounts = ARRAY_COUNT(sItemTable1);
	}
	else
	{
		gItemTable = sItemTable0;
		gItemTableCounts = ARRAY_COUNT(sItemTable0);
	}
}

void ItemUseOutOfBattle_PowderBox(u8 taskId)
{
	SetMainCallback2(CB2_PowderBoxMain);
    if (gTasks[taskId].tUsingRegisteredKeyItem == 0)
        gMain.savedCallback = CB2_ReturnToBagMenu;
    else
        gMain.savedCallback = CB2_ReturnToFieldContinueScriptPlayMapMusic;
    DestroyTask(taskId);
}

static void CB2_PowderBoxMain(void)
{
    gMain.state = 0;
    SetMainCallback2(CB2_ShowPowderBoxMain);
    FreeBagItemListBuffers();
}

static void CB2_ShowPowderBoxMain(void)
{
    switch (gMain.state)
    {
        default:
        case 0:
            SetVBlankCallback(NULL);
            break;
        case 1:
            ResetPaletteFade();
            ScanlineEffect_Stop();
            ResetTasks();
            ResetSpriteData();
            break;
        case 2:
            SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG3CNT, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG2CNT, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG1CNT, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG0CNT, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG3HOFS, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG3VOFS, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG2HOFS, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG2VOFS, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG1HOFS, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG1VOFS, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG0HOFS, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BG0VOFS, DISPCNT_MODE_0);
            DmaFill16(3, 0, VRAM, VRAM_SIZE);
            DmaFill32(3, 0, OAM, OAM_SIZE);
            DmaFill16(3, 0, PLTT, PLTT_SIZE);
            ResetBgsAndClearDma3BusyFlags(0);
            InitBgsFromTemplates(0, sPhoneBgTemplates, 2);
            gPhonePtr = AllocZeroed(0x1000);
            SetBgTilemapBuffer(1, gPhonePtr);
            SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP);
            ShowBg(0);
            ShowBg(1);
            SetGpuReg(REG_OFFSET_BLDCNT, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BLDALPHA, DISPCNT_MODE_0);
            SetGpuReg(REG_OFFSET_BLDY, DISPCNT_MODE_0);
            break;
        case 3:
            ResetTempTileDataBuffers();
            DecompressAndCopyTileDataToVram(1, sDiplomaTiles, 0, 0, 0);
            CopyToBgTilemapBuffer(1, sDiplomaTilemap, 0, 0);
            break;
        case 4:
            if (FreeTempTileDataBuffersIfPossible())
                return;
            break;
        case 5:
            LoadPalette(sDiplomaPalettes, 0, 0x40);
            break;
        case 6:
            LoadBgTiles(0, GetWindowFrameTilesPal(gSaveBlock2Ptr->optionsWindowFrameType)->tiles, 0x120, 0x2FF);
            LoadPalette(GetWindowFrameTilesPal(gSaveBlock2Ptr->optionsWindowFrameType)->pal, 0x40, 0x40);
            LoadPalette(sMainMenuTextPal, 0x80, 0x20);
            InitWindows(sPhoneWinTemplates);
            DrawStdFrameWithCustomTileAndPalette(1, 0, 0x300, 4);
            break;
        case 7:
            DrawTextWinPowderBox();
            break;
        case 8:
        {
            ChangeBgX(1, 0x10000, 0);
            CopyBgTilemapBufferToVram(0);
            CopyBgTilemapBufferToVram(1);
            break;
        }
        case 9:
        {
            u8 taskId;

            taskId = CreateTask(Task_PowderBoxFadeIn, 0);
            gTasks[taskId].SELECTION = gSaveBlock2Ptr->playerAppearance;
            PrintOWName(gTasks[taskId].SELECTION);
            CreatePlayerOW(taskId);
        }
        case 10:
            BeginNormalPaletteFade(0xFFFFFFFF, 0, 0x10, 0, 0);
            SetVBlankCallback(VBlankCB);
            SetMainCallback2(MainCB2);
            return;
    }
    gMain.state++;
}

static void CreatePlayerOW(u8 taskId)
{
    u16 i;
    u8 spriteId;
    u16 rivalGfxId;

    for (i = 0; i < PLAYER_APPEARANCE_COUNT; i++)
    {
        rivalGfxId = GetPlayerAvatarGraphicsIdByAppearanceAndGender(i, gSaveBlock2Ptr->playerGender);
        spriteId = AddPseudoObjectEvent(rivalGfxId, SpriteCallbackDummy, 120, 66, 0);
        gSprites[spriteId].oam.priority = 3;
        StartSpriteAnim(&gSprites[spriteId], 4);
        gTasks[taskId].data[3 + i] = spriteId;
        if (gTasks[taskId].SELECTION != i)
            gSprites[spriteId].invisible = TRUE;
    }
}

static void Task_PowderBoxFadeIn(u8 taskId)
{
    if (!gPaletteFade.active)
        gTasks[taskId].func = Task_PowderBoxProcessInput;
}

static void Task_PowderBoxProcessInput(u8 taskId)
{
    if (gMain.newKeys & DPAD_RIGHT)
    {
        gSprites[gTasks[taskId].data[3 + gTasks[taskId].SELECTION]].invisible = TRUE;
        if (gTasks[taskId].SELECTION < PLAYER_APPEARANCE_COUNT - 1)
            gTasks[taskId].SELECTION++;
        else
            gTasks[taskId].SELECTION = 0;
        gSprites[gTasks[taskId].data[3 + gTasks[taskId].SELECTION]].invisible = FALSE;
        PrintOWName(gTasks[taskId].SELECTION);
    }
    else if (gMain.newKeys & DPAD_LEFT)
    {
        gSprites[gTasks[taskId].data[3 + gTasks[taskId].SELECTION]].invisible = TRUE;
        if (gTasks[taskId].SELECTION > 0)
            gTasks[taskId].SELECTION--;
        else
            gTasks[taskId].SELECTION = PLAYER_APPEARANCE_COUNT - 1;
        gSprites[gTasks[taskId].data[3 + gTasks[taskId].SELECTION]].invisible = FALSE;
        PrintOWName(gTasks[taskId].SELECTION);
    }
    else if (gMain.newKeys & A_BUTTON)
    {
        if (gTasks[taskId].SELECTION != gSaveBlock2Ptr->playerAppearance)
        {
            gTasks[taskId].STEP = 0;
            gTasks[taskId].func = Task_ChangeOWSuccess;
        }
        else
        {
            gTasks[taskId].STEP = 0;
            gTasks[taskId].func = Task_ChangeOWFailed;
        }
    }
    else if (gMain.newKeys & B_BUTTON)
    {
        BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0);
        gTasks[taskId].func = Task_FuncFadeOut;
    }
}

static void Task_ChangeOWSuccess(u8 taskId)
{
    switch (gTasks[taskId].STEP)
    {
        case 0:
        {
            u8 dst[50];

            FillWindowPixelBuffer(1, PIXEL_FILL(1));
            StringCopy(dst, gText_OWVar1ChangeToVar2_1);
            StringAppend(dst, OWNames[gSaveBlock2Ptr->playerAppearance][gSaveBlock2Ptr->playerGender]);
            StringAppend(dst, gText_OWVar1ChangeToVar2_2);
            StringAppend(dst, OWNames[gTasks[taskId].SELECTION][gSaveBlock2Ptr->playerGender]);
            StringAppend(dst, gText_OWVar1ChangeToVar2_3);
            AddTextPrinterParameterized(1, 1, dst,GetStringCenterAlignXOffset(1, dst, 28 * 8), 1, 0xFF,NULL);
            PutWindowTilemap(1);
            CopyWindowToVram(1, 3);
            break;
        }
        case 1:
        {
            if (gMain.newKeys & (A_BUTTON | B_BUTTON))
            {
                SetPlayerAvatarAppearance(gTasks[taskId].SELECTION);
                DrawTextWinPowderBox();
                gTasks[taskId].func = Task_PowderBoxProcessInput;
            }
            return;
        }
    }
    gTasks[taskId].STEP++;
}

static void Task_ChangeOWFailed(u8 taskId)
{
    switch (gTasks[taskId].STEP)
    {
        case 0:
            FillWindowPixelBuffer(1, PIXEL_FILL(1));
            AddTextPrinterParameterized(1, 1, gText_ChangeOWFailed,GetStringCenterAlignXOffset(1, gText_ChangeOWFailed, 28 * 8), 1, 0xFF,NULL);
            PutWindowTilemap(1);
            CopyWindowToVram(1, 3);
            break;
        case 1:
        {
            if (gMain.newKeys & (A_BUTTON | B_BUTTON))
            {
                DrawTextWinPowderBox();
                gTasks[taskId].func = Task_PowderBoxProcessInput;
            }
            return;
        }
    }
    gTasks[taskId].STEP++;
}

static void DrawTextWinPowderBox(void)
{
    FillWindowPixelBuffer(1, PIXEL_FILL(1));
    AddTextPrinterParameterized(1, 1, gText_ControlPowderBox, GetStringCenterAlignXOffset(1, gText_ControlPowderBox, 28 * 8), 1, 0xFF, NULL);
    PutWindowTilemap(1);
    CopyWindowToVram(1, 3);
}

static const u8 OWNames[PLAYER_APPEARANCE_COUNT][GENDER_COUNT][7] = {
    {_("佑树"),   _("小遥")},
    {_("赤红"),   _("小蓝")},
    {_("小智"),   _("瑟蕾娜")},
};

static void PrintOWName(u8 appearance)
{
    FillWindowPixelBuffer(0, PIXEL_FILL(0));
    AddTextPrinterParameterized3(0, 1, GetStringCenterAlignXOffset(1, OWNames[appearance][gSaveBlock2Ptr->playerGender], 28 * 8), 32, color, 0xFF, OWNames[appearance][gSaveBlock2Ptr->playerGender]);
    PutWindowTilemap(0);
    CopyWindowToVram(0, 3);
}

void ItemUseOutOfBattle_Phone(u8 taskId)
{
    gSpecialVar_0x8004 = gTasks[taskId].tUsingRegisteredKeyItem;
	SetMainCallback2(CB2_PhoneMain);
    DestroyTask(taskId);
}

void CB2_PhoneMain(void)
{
    gMain.state = 0;
    SetMainCallback2(CB2_ShowPhoneMain);
    FreeBagItemListBuffers();
    if (gSpecialVar_0x8004 == 0 || gSpecialVar_0x8004 == 2)
        gMain.savedCallback = CB2_ReturnToBagMenu;
    else
        gMain.savedCallback = CB2_ReturnToFieldContinueScriptPlayMapMusic;
}

static void CB2_ShowPhoneMain(void)
{
	switch (gMain.state)
	{
		default:
		case 0:
			SetVBlankCallback(NULL);
			break;
		case 1:
			ResetPaletteFade();
			ScanlineEffect_Stop();
			ResetTasks();
			ResetSpriteData();
			break;
		case 2:
			SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG3CNT, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG2CNT, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG1CNT, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG0CNT, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG3HOFS, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG3VOFS, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG2HOFS, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG2VOFS, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG1HOFS, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG1VOFS, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG0HOFS, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BG0VOFS, DISPCNT_MODE_0);
			DmaFill16(3, 0, VRAM, VRAM_SIZE);
			DmaFill32(3, 0, OAM, OAM_SIZE);
			DmaFill16(3, 0, PLTT, PLTT_SIZE);
			ResetBgsAndClearDma3BusyFlags(0);
			InitBgsFromTemplates(0, sPhoneBgTemplates, 2);
			gPhonePtr = AllocZeroed(0x1000);
			SetBgTilemapBuffer(1, gPhonePtr);
			SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP);
			ShowBg(0);
			ShowBg(1);
			SetGpuReg(REG_OFFSET_BLDCNT, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BLDALPHA, DISPCNT_MODE_0);
			SetGpuReg(REG_OFFSET_BLDY, DISPCNT_MODE_0);
			break;
		case 3:
			ResetTempTileDataBuffers();
			DecompressAndCopyTileDataToVram(1, GetTiles(gSaveBlock1Ptr->gTileType), 0, 0, 0);
			CopyToBgTilemapBuffer(1, GetTileMap(gSaveBlock1Ptr->gTileType), 0, 0);
			break;
		case 4:
			if (FreeTempTileDataBuffersIfPossible())
				return;
			break;
		case 5:
			LoadPalette(GetPalette(gSaveBlock1Ptr->gTileType), 0, 0x40);
			break;
		case 6:
			LoadBgTiles(0, GetWindowFrameTilesPal(gSaveBlock2Ptr->optionsWindowFrameType)->tiles, 0x120, 0x2FF);
			LoadPalette(GetWindowFrameTilesPal(gSaveBlock2Ptr->optionsWindowFrameType)->pal, 0x40, 0x40);
			LoadPalette(sMainMenuTextPal, 0x80, 0x20);
			InitWindows(sPhoneWinTemplates);
			DrawStdFrameWithCustomTileAndPalette(1, 0, 0x300, 4);
			break;
		case 7:
			DrawTextWinMain();
			DrawOptionsWinMain();
			break;
		case 8:
		{
			if (GetMode(gSaveBlock1Ptr->gTileType))
				ChangeBgX(1, 0x10000, 0);
			else
				ChangeBgX(1, 0, 0);
				
			CopyBgTilemapBufferToVram(0);
			CopyBgTilemapBufferToVram(1);
			break;
		}
		case 9:
		{
			u16 i;
			u8 taskId, spriteId;
			void *decompressionbuffer;
			struct SpriteSheet sheet;
			struct SpritePalette palette;
			
			decompressionbuffer = AllocZeroed(0x160); //16*16/2 X
			LZDecompressWram(sCursorGfx, decompressionbuffer);
			sheet.data = decompressionbuffer;
			sheet.size = 0x80;
			sheet.tag = 0x1300;
			LoadSpriteSheet(&sheet);
			palette.data = gFrontierPassCursor_Pal;
			palette.tag = 0x1300;
			LoadSpritePalette(&palette);
			spriteId = CreateSprite(&CursorTemplate, 0, 0, 0);
			gSprites[spriteId].vFlip = TRUE;
			Free(decompressionbuffer);
			
			taskId = CreateTask(Task_FuncFadeIn, 0);
			gTasks[taskId].CURSORID = spriteId;
            if (2 == gSpecialVar_0x8004)
            {
                gTasks[taskId].SELECTION = 4;
                ChangeCursorPos(gTasks[taskId].CURSORID, gTasks[taskId].SELECTION, 0);
            }
            else
                ChangeCursorPos(spriteId, 0, 0);

			LoadMonIconPalettes();
			for (i = 0; i < gPlayerPartyCount; i++)
			{
				spriteId = CreateMonIcon(GetMonData(&gPlayerParty[i], 0xB, NULL), SpriteCB_MonIcon, PMPosX[i], 0x10, 80, GetMonData(&gPlayerParty[i], 0, NULL), 1);
				gSprites[spriteId].invisible = TRUE;
				gTasks[taskId].data[4 + i] = spriteId;
			}
			
			LoadgItemTable();
			break;
		}
		case 10:
			BeginNormalPaletteFade(0xFFFFFFFF, 0, 0x10, 0, 0);
			SetVBlankCallback(VBlankCB);
			SetMainCallback2(MainCB2);
			return;
	}
	gMain.state++;
}

static void Task_FuncFadeIn(u8 taskId)
{
    if (!gPaletteFade.active)
        gTasks[taskId].func = Task_FuncProcessInputMain;
}

static void Task_FuncProcessInputMain(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
			DrawTextWinMain();
			DrawOptionsWinMain();
			break;
		case 1:
		{
			if (gMain.newKeys & DPAD_RIGHT)
			{
				if (4 == gTasks[taskId].SELECTION)
					gTasks[taskId].SELECTION = 0;
				else
					gTasks[taskId].SELECTION++;
				
				ChangeCursorPos(gTasks[taskId].CURSORID, gTasks[taskId].SELECTION, 0);
			}
			else if (gMain.newKeys & DPAD_LEFT)
			{
				if (0 == gTasks[taskId].SELECTION)
					gTasks[taskId].SELECTION = 4;
                else
					gTasks[taskId].SELECTION--;
				
				ChangeCursorPos(gTasks[taskId].CURSORID, gTasks[taskId].SELECTION, 0);
			}
			else if (gMain.newKeys & DPAD_UP)
			{
				if (3 == gTasks[taskId].SELECTION)
					gTasks[taskId].SELECTION = 0;
                else if (4 == gTasks[taskId].SELECTION)
                    gTasks[taskId].SELECTION = 2;
				else if (0 == gTasks[taskId].SELECTION)
					gTasks[taskId].SELECTION = 3;
                else
                    gTasks[taskId].SELECTION = 4;
				
				ChangeCursorPos(gTasks[taskId].CURSORID, gTasks[taskId].SELECTION, 0);
			}
			else if (gMain.newKeys & DPAD_DOWN)
			{
				if (0 == gTasks[taskId].SELECTION)
					gTasks[taskId].SELECTION = 3;
                else if (1 == gTasks[taskId].SELECTION || 2 == gTasks[taskId].SELECTION)
                    gTasks[taskId].SELECTION = 4;
                else if (3 == gTasks[taskId].SELECTION)
                    gTasks[taskId].SELECTION = 0;
				else
					gTasks[taskId].SELECTION = 2;
				
				ChangeCursorPos(gTasks[taskId].CURSORID, gTasks[taskId].SELECTION, 0);
			}
			else if (gMain.newKeys & B_BUTTON)
			{
				BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0);
				gTasks[taskId].func = Task_FuncFadeOut;
			}
			else if (gMain.newKeys & R_BUTTON)
			{
				if (gSaveBlock1Ptr->gTileType < ARRAY_COUNT(gTileMaps) - 1)
					gSaveBlock1Ptr->gTileType++;
				else
					gSaveBlock1Ptr->gTileType = 0;
				
				gTasks[taskId].STEP = 0;
				gTasks[taskId].func = Task_ChangeBg;
			}
			else if (gMain.newKeys & L_BUTTON)
			{
				if (gSaveBlock1Ptr->gTileType > 0)
					gSaveBlock1Ptr->gTileType--;
				else
					gSaveBlock1Ptr->gTileType = ARRAY_COUNT(gTileMaps) - 1;
				
				gTasks[taskId].STEP = 0;
				gTasks[taskId].SELECTION = 0;
				gTasks[taskId].func = Task_ChangeBg;
			}
			else if (gMain.newKeys & A_BUTTON)
			{
				if (0 == gTasks[taskId].SELECTION) //手机设置
				{
					gTasks[taskId].STEP = 0;
					gTasks[taskId].SELECTION = 0;
					ChangeCursorPos(gTasks[taskId].CURSORID, 0, 1);
					gTasks[taskId].func = Task_FuncProcessInputFunc;
					
				}
				else if (1 == gTasks[taskId].SELECTION) //购物
				{
					gTasks[taskId].STEP = 0;
					gTasks[taskId].SELECTION = 0;
					gSprites[gTasks[taskId].CURSORID].invisible = TRUE;
					gTasks[taskId].func = Task_FuncProcessInputBuy;
					
				}
				else if (2 == gTasks[taskId].SELECTION) //查看个体努力
				{
					gTasks[taskId].STEP = 0;
					gTasks[taskId].SELECTION = 0;
					ChangeCursorPos(gTasks[taskId].CURSORID, 0, 2);
					gTasks[taskId].func = Task_FuncProcessInputEVIV;
				}
				else if (3 == gTasks[taskId].SELECTION) //打开电脑
				{
					gTasks[taskId].STEP = 0;
					gTasks[taskId].func = Task_FuncOpenPC;
				}
                else //图鉴导航
                {
                    if (!FlagGet(FLAG_SYS_DEXNAV_GET))
                    {
                        gTasks[taskId].STEP = 0;
                        gTasks[taskId].func = Task_FuncBuyDexNev;
                    }
                    else
                    {
                        if (HasMapMons())
                        {
                            if (gSpecialVar_0x8004 < 1)
                                gSpecialVar_0x8004 += 2;
                            gTasks[taskId].func = Task_OpenDexNavFromStartMenu;
                        }
                        else
                        {
                            gTasks[taskId].STEP = 0;
                            gTasks[taskId].func = Task_NoWildMonHere;
                        }
                    }
                }
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_FuncBuyDexNev(u8 taskId)
{
    switch (gTasks[taskId].STEP)
    {
        case 0:
            FillWindowPixelBuffer(1, PIXEL_FILL(1));
            AddTextPrinterParameterized(1, 1, gText_BuyDexNav1, GetStringCenterAlignXOffset(1, gText_BuyDexNav1, 28 * 8), 1, 0xFF, NULL);
            PutWindowTilemap(1);
            CopyWindowToVram(1, 3);
            break;
        case 1:
            if (gMain.newKeys & (A_BUTTON | B_BUTTON))
                break;
            return;
        case 2:
            FillWindowPixelBuffer(1, PIXEL_FILL(1));
            AddTextPrinterParameterized(1, 1, gText_BuyDexNav2, GetStringCenterAlignXOffset(1, gText_BuyDexNav2, 28 * 8), 1, 0xFF, NULL);
            PutWindowTilemap(1);
            CopyWindowToVram(1, 3);
            break;
        case 3:
        {
            if (gMain.newKeys & A_BUTTON)
            {
                if (GetMoney(&gSaveBlock1Ptr->money) >= 100000)
                {
                    RemoveMoney(&gSaveBlock1Ptr->money, 100000);
                    FillWindowPixelBuffer(1, PIXEL_FILL(1));
                    AddTextPrinterParameterized(1, 1, gText_UnlcokDexNav, GetStringCenterAlignXOffset(1, gText_UnlcokDexNav, 28 * 8), 1, 0xFF, NULL);
                    PutWindowTilemap(1);
                    CopyWindowToVram(1, 3);
                    FlagSet(FLAG_SYS_DEXNAV_GET);
                }
                else
                {
                    FillWindowPixelBuffer(1, PIXEL_FILL(1));
                    AddTextPrinterParameterized(1, 1, gText_NoEnoughMoney, GetStringCenterAlignXOffset(1, gText_NoEnoughMoney, 28 * 8), 1, 0xFF, NULL);
                    PutWindowTilemap(1);
                    CopyWindowToVram(1, 3);
                }
                break;
            }
            else if (gMain.newKeys & B_BUTTON)
                gTasks[taskId].STEP = 5;
            return;
        }
        case 4:
            if (gMain.newKeys & (A_BUTTON | B_BUTTON))
                break;
            return;
        case 5:
            gTasks[taskId].STEP = 0;
            gTasks[taskId].func = Task_FuncProcessInputMain;
            return;
    }
    gTasks[taskId].STEP++;
}

static void Task_FuncProcessInputFunc(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
			DrawTextWinFunc();
			DrawOptionsWinFunc();
			break;
		case 1:
		{
			if (gMain.newKeys & DPAD_RIGHT)
			{
				if (gTasks[taskId].SELECTION < 4)
					gTasks[taskId].SELECTION += 4;
				else
					gTasks[taskId].SELECTION -= 4;
				
				DrawOptionsWinFunc();
				ChangeCursorPos(gTasks[taskId].CURSORID, gTasks[taskId].SELECTION, 1);
			}
			else if (gMain.newKeys & DPAD_LEFT)
			{
				if (gTasks[taskId].SELECTION > 3)
					gTasks[taskId].SELECTION -= 4;
				else
					gTasks[taskId].SELECTION += 4;
				
				DrawOptionsWinFunc();
				ChangeCursorPos(gTasks[taskId].CURSORID, gTasks[taskId].SELECTION, 1);
			}
			else if (gMain.newKeys & DPAD_UP)
			{
				if (0 == gTasks[taskId].SELECTION)
					gTasks[taskId].SELECTION = 3;
				else if (4 == gTasks[taskId].SELECTION)
					gTasks[taskId].SELECTION = 7;
				else
					gTasks[taskId].SELECTION--;
				
				DrawOptionsWinFunc();
				ChangeCursorPos(gTasks[taskId].CURSORID, gTasks[taskId].SELECTION, 1);
			}
			else if (gMain.newKeys & DPAD_DOWN)
			{
				if (3 == gTasks[taskId].SELECTION)
					gTasks[taskId].SELECTION = 0;
				else if (7 == gTasks[taskId].SELECTION)
					gTasks[taskId].SELECTION = 4;
				else
					gTasks[taskId].SELECTION++;
				
				DrawOptionsWinFunc();
				ChangeCursorPos(gTasks[taskId].CURSORID, gTasks[taskId].SELECTION, 1);
			}
			else if (gMain.newKeys & A_BUTTON)
			{
				gSaveBlock1Ptr->gFlagTable.ftu8 ^= (1 << gTasks[taskId].SELECTION);
				DrawOptionsWinFunc();
			}
			else if (gMain.newKeys & B_BUTTON)
			{
				u16 i, j;
				
				for (i = 1, j = 0; i < 8; i++)
				{
					if ((gSaveBlock1Ptr->gFlagTable.ftu8 >> i) & 1)
						j++;
				}
				
				if ((0 == j) && gSaveBlock1Ptr->gFlagTable.ftstruct.enable)
				{
					gTasks[taskId].STEP = 0;
					gTasks[taskId].func = Task_PrintLeastOne;
				}
				else
				{
					gTasks[taskId].STEP = 0;
					gTasks[taskId].SELECTION = 0;
					ChangeCursorPos(gTasks[taskId].CURSORID, 0, 0);
					gTasks[taskId].func = Task_FuncProcessInputMain;
				}
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_FuncProcessInputBuy(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
			gTasks[taskId].COUNT = 0;
			DrawTextWinBuy();
			DrawOptionsWinBuy(gTasks[taskId].SELECTION, gTasks[taskId].COUNT);
			break;
		case 1:
		{
			if (gMain.newKeys & DPAD_DOWN)
			{
				if (gTasks[taskId].SELECTION < gItemTableCounts - 1)
					gTasks[taskId].SELECTION++;
				
				DrawOptionsWinBuy(gTasks[taskId].SELECTION, gTasks[taskId].COUNT);
			}
			else if (gMain.newKeys & DPAD_UP)
			{
				if (gTasks[taskId].SELECTION > 0)
					gTasks[taskId].SELECTION--;
				
				DrawOptionsWinBuy(gTasks[taskId].SELECTION, gTasks[taskId].COUNT);
			}
			else if (gMain.newKeys & B_BUTTON)
			{
				gTasks[taskId].STEP = 0;
				gTasks[taskId].SELECTION = 1;
				gSprites[gTasks[taskId].CURSORID].invisible = FALSE;
				ChangeCursorPos(gTasks[taskId].CURSORID, 1, 0);
				gTasks[taskId].func = Task_FuncProcessInputMain;
			}
			else if (gMain.newKeys & A_BUTTON)
			{
				gTasks[taskId].STEP = 0;
				gTasks[taskId].COUNT = 1;
				gTasks[taskId].func = Task_FuncProcessInputCount;
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_FuncProcessInputCount(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
			DrawTextWinCount(gTasks[taskId].COUNT);
			DrawOptionsWinBuy(gTasks[taskId].SELECTION, gTasks[taskId].COUNT);
			break;
		case 1:
		{
			if (gMain.newKeys & DPAD_UP)
			{
				if (gTasks[taskId].COUNT < 99)
					gTasks[taskId].COUNT++;
				else
					gTasks[taskId].COUNT = 1;
					
				DrawTextWinCount(gTasks[taskId].COUNT);
				DrawOptionsWinBuy(gTasks[taskId].SELECTION, gTasks[taskId].COUNT);
			}
			if (gMain.newKeys & DPAD_DOWN)
			{
				if (gTasks[taskId].COUNT > 1)
					gTasks[taskId].COUNT--;
				else
					gTasks[taskId].COUNT = 99;
					
				DrawTextWinCount(gTasks[taskId].COUNT);
				DrawOptionsWinBuy(gTasks[taskId].SELECTION, gTasks[taskId].COUNT);
			}
			if (gMain.newKeys & DPAD_LEFT)
			{
				if (gTasks[taskId].COUNT > 10)
					gTasks[taskId].COUNT -= 10;
				else
					gTasks[taskId].COUNT = 1;
					
				DrawTextWinCount(gTasks[taskId].COUNT);
				DrawOptionsWinBuy(gTasks[taskId].SELECTION, gTasks[taskId].COUNT);
			}
			if (gMain.newKeys & DPAD_RIGHT)
			{
				if (gTasks[taskId].COUNT < 90)
					gTasks[taskId].COUNT += 10;
				else
					gTasks[taskId].COUNT = 99;
					
				DrawTextWinCount(gTasks[taskId].COUNT);
				DrawOptionsWinBuy(gTasks[taskId].SELECTION, gTasks[taskId].COUNT);
			}
			if (gMain.newKeys & B_BUTTON)
			{
				gTasks[taskId].STEP = 0;
				gTasks[taskId].func = Task_FuncProcessInputBuy;
			}
			if (gMain.newKeys & A_BUTTON)
			{
				if (IsEnoughMoney(&gSaveBlock1Ptr->money, (((ItemId_GetPrice(gItemTable[gTasks[taskId].SELECTION]) >> GetPriceReduction(1)) * 3) >> 1) * gTasks[taskId].COUNT))
				{
					if (AddBagItem(gItemTable[gTasks[taskId].SELECTION], gTasks[taskId].COUNT))
					{
						RemoveMoney(&gSaveBlock1Ptr->money, (((ItemId_GetPrice(gItemTable[gTasks[taskId].SELECTION]) >> GetPriceReduction(1)) * 3) >> 1) * gTasks[taskId].COUNT);
						DrawOptionsWinBuy(gTasks[taskId].SELECTION, gTasks[taskId].COUNT);
						gTasks[taskId].STEP = 0;
						gTasks[taskId].func = Task_FuncProcessInputBuySuccess;
					}
					else
					{
						gTasks[taskId].STEP = 0;
						gTasks[taskId].func = Task_NeedMoreRoom;
					}
				}
				else
				{
					gTasks[taskId].STEP = 0;
					gTasks[taskId].func = Task_NoEnoughMoney;
				}
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_FuncProcessInputBuySuccess(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
		{
			u8 dst[50];
			u8 dst2[15];
			
			FillWindowPixelBuffer(1, PIXEL_FILL(1));
			StringCopy(dst, gText_SuccessBuy);
			GetItemName(dst2, gItemTable[gTasks[taskId].SELECTION]);
			StringAppend(dst, dst2);
			ConvertIntToDecimalStringN(dst2, gTasks[taskId].COUNT, 0, 2);
			StringAppend(dst, dst2);
			StringAppend(dst, gText_Ge);
			AddTextPrinterParameterized(1, 1, dst, GetStringCenterAlignXOffset(1, dst, 28 * 8), 1, 0xFF, NULL);

			PutWindowTilemap(1);
			CopyWindowToVram(1, 3);
			break;
		}
		case 1:
		{
			if (gMain.newKeys & (A_BUTTON | B_BUTTON))
			{
				gTasks[taskId].STEP = 0;
				gTasks[taskId].func = Task_FuncProcessInputBuy;
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_NeedMoreRoom(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
			FillWindowPixelBuffer(1, PIXEL_FILL(1));
			AddTextPrinterParameterized(1, 1, gText_NeedMoreRoom, GetStringCenterAlignXOffset(1, gText_NeedMoreRoom, 28 * 8), 1, 0xFF, NULL);
			PutWindowTilemap(1);
			CopyWindowToVram(1, 3);
			break;
		case 1:
		{
			if (gMain.newKeys & (A_BUTTON | B_BUTTON))
			{
				gTasks[taskId].STEP = 0;
				gTasks[taskId].func = Task_FuncProcessInputCount;
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_NoEnoughMoney(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
			FillWindowPixelBuffer(1, PIXEL_FILL(1));
			AddTextPrinterParameterized(1, 1, gText_NoEnoughMoney, GetStringCenterAlignXOffset(1, gText_NoEnoughMoney, 28 * 8), 1, 0xFF, NULL);
			PutWindowTilemap(1);
			CopyWindowToVram(1, 3);
			break;
		case 1:
		{
			if (gMain.newKeys & (A_BUTTON | B_BUTTON))
			{
				gTasks[taskId].STEP = 0;
				gTasks[taskId].func = Task_FuncProcessInputCount;
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_NoWildMonHere(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
			FillWindowPixelBuffer(1, PIXEL_FILL(1));
			AddTextPrinterParameterized(1, 1, gText_NoWildMonHere, GetStringCenterAlignXOffset(1, gText_NoWildMonHere, 28 * 8), 1, 0xFF, NULL);
			PutWindowTilemap(1);
			CopyWindowToVram(1, 3);
			break;
		case 1:
		{
			if (gMain.newKeys & (A_BUTTON | B_BUTTON))
			{
				gTasks[taskId].STEP = 0;
				gTasks[taskId].func = Task_FuncProcessInputMain;
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_FuncFadeOut(u8 taskId)
{
	if (!gPaletteFade.active)
    {
		Free(gPhonePtr);
        DestroyTask(taskId);
        FreeAllWindowBuffers();
        SetMainCallback2(gMain.savedCallback);
    }
}

static void Task_ChangeBg(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
			BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0);
			break;
		case 1:
		{
			if (!gPaletteFade.active)
			{
				SetVBlankCallback(NULL);
				break;
			}
			return;
		}
		case 2:
			ResetTempTileDataBuffers();
			DecompressAndCopyTileDataToVram(1, GetTiles(gSaveBlock1Ptr->gTileType), 0, 0, 0);
			CopyToBgTilemapBuffer(1, GetTileMap(gSaveBlock1Ptr->gTileType), 0, 0);
			break;
		case 3:
			if (FreeTempTileDataBuffersIfPossible())
				return;
			break;
		case 4:
			LoadPalette(GetPalette(gSaveBlock1Ptr->gTileType), 0, 0x40);
			break;
		case 5:
		{
			if (GetMode(gSaveBlock1Ptr->gTileType))
				ChangeBgX(1, 0x10000, 0);
			else
				ChangeBgX(1, 0, 0);
			
			CopyBgTilemapBufferToVram(1);
			break;
		}
		case 6:
			BeginNormalPaletteFade(0xFFFFFFFF, 0, 0x10, 0, 0);
			SetVBlankCallback(VBlankCB);
			break;
		case 7:
		{
			if (!gPaletteFade.active)
			{
				gTasks[taskId].func = Task_FuncProcessInputMain;
				gTasks[taskId].STEP = 0;
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_FuncProcessInputEVIV(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
		{
			u16 i;
			
			for (i = 0; i < gPlayerPartyCount; i++)
				gSprites[gTasks[taskId].data[4 + i]].invisible = FALSE;
			break;
		}
		case 1:
			gTasks[taskId].TYPE = 0;
			DrawTextWinEVIV();
			DrawOptionsWinEVIV(gTasks[taskId].SELECTION, gTasks[taskId].TYPE);
			break;
		case 2:
		{
			if (gMain.newKeys & DPAD_RIGHT)
			{
				if (gTasks[taskId].SELECTION < gPlayerPartyCount - 1)
					gTasks[taskId].SELECTION++;
				else
					gTasks[taskId].SELECTION = 0;
				
				ChangeCursorPos(gTasks[taskId].CURSORID, gTasks[taskId].SELECTION, 2);
				DrawOptionsWinEVIV(gTasks[taskId].SELECTION, gTasks[taskId].TYPE);
			}
			if (gMain.newKeys & DPAD_LEFT)
			{
				if (gTasks[taskId].SELECTION > 0)
					gTasks[taskId].SELECTION--;
				else
					gTasks[taskId].SELECTION = gPlayerPartyCount - 1;
				
				ChangeCursorPos(gTasks[taskId].CURSORID, gTasks[taskId].SELECTION, 2);
				DrawOptionsWinEVIV(gTasks[taskId].SELECTION, gTasks[taskId].TYPE);
			}
			else if (gMain.newKeys & A_BUTTON)
			{
				if (0 == gTasks[taskId].TYPE)
					gTasks[taskId].TYPE = 1;
				else
					gTasks[taskId].TYPE = 0;
				
				DrawOptionsWinEVIV(gTasks[taskId].SELECTION, gTasks[taskId].TYPE);
			}
			else if (gMain.newKeys & B_BUTTON)
			{
				u16 i;
			
				for (i = 0; i < gPlayerPartyCount; i++)
					gSprites[gTasks[taskId].data[4 + i]].invisible = TRUE;
				
				gTasks[taskId].STEP = 0;
				gTasks[taskId].SELECTION = 2;
				ChangeCursorPos(gTasks[taskId].CURSORID, 2, 0);
				gTasks[taskId].func = Task_FuncProcessInputMain;
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_PrintLeastOne(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
			FillWindowPixelBuffer(1, PIXEL_FILL(1));
			AddTextPrinterParameterized(1, 1, gText_LeastOne, GetStringCenterAlignXOffset(1, gText_LeastOne, 28 * 8), 1, 0xFF, NULL);
			PutWindowTilemap(1);
			CopyWindowToVram(1, 3);
			break;
		case 1:
		{
			if (gMain.newKeys & (A_BUTTON | B_BUTTON))
			{
				gTasks[taskId].STEP = 0;
				gTasks[taskId].func = Task_FuncProcessInputFunc;
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_FuncOpenPC(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
		{
			if (GetMoney(&gSaveBlock1Ptr->money) >= 10000)
			{
				FillWindowPixelBuffer(1, PIXEL_FILL(1));
				AddTextPrinterParameterized(1, 1, gText_Cost5Percent, GetStringCenterAlignXOffset(1, gText_Cost5Percent, 28 * 8), 1, 0xFF, NULL);
				PutWindowTilemap(1);
				CopyWindowToVram(1, 3);
				break;
			}
			else
			{
				gTasks[taskId].STEP = 0;
				gTasks[taskId].func = Task_FuncProcessNoQualification;
				return;
			}
		}
		case 1:
		{
			if (gMain.newKeys & A_BUTTON)
			{
				RemoveMoney(&gSaveBlock1Ptr->money, GetMoney(&gSaveBlock1Ptr->money) / 20);
				gMain.savedCallback = CB2_ReturnToFieldContinueScriptPlayMapMusic;
				gIsFromPhone = TRUE;
				ScriptContext1_SetupScript(EventScript_PC); //电脑
				BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0);
				gTasks[taskId].func = Task_FuncFadeOut;
				
			}
			else if (gMain.newKeys & B_BUTTON)
			{
				gTasks[taskId].STEP = 0;
				gTasks[taskId].func = Task_FuncProcessInputMain;
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void Task_FuncProcessNoQualification(u8 taskId)
{
	switch (gTasks[taskId].STEP)
	{
		case 0:
			FillWindowPixelBuffer(1, PIXEL_FILL(1));
			AddTextPrinterParameterized(1, 1, gText_NoQualification, GetStringCenterAlignXOffset(1, gText_NoQualification, 28 * 8), 1, 0xFF, NULL);
			PutWindowTilemap(1);
			CopyWindowToVram(1, 3);
			break;
		case 1:
		{
			if (gMain.newKeys & (A_BUTTON | B_BUTTON))
			{
				gTasks[taskId].STEP = 0;
				gTasks[taskId].func = Task_FuncProcessInputMain;
			}
			return;
		}
	}
	gTasks[taskId].STEP++;
}

static void DrawTextWinMain(void)
{
	FillWindowPixelBuffer(1, PIXEL_FILL(1));
	AddTextPrinterParameterized(1, 1, gText_ControlMain, GetStringCenterAlignXOffset(1, gText_ControlMain, 28 * 8), 1, 0xFF, NULL);
	PutWindowTilemap(1);
	CopyWindowToVram(1, 3);
}

static void DrawOptionsWinMain(void)
{
	FillWindowPixelBuffer(0, PIXEL_FILL(0));
	AddTextPrinterParameterized3(0, 1, 16, 40, color, 0xFF, gText_Func);
	AddTextPrinterParameterized3(0, 1, GetStringCenterAlignXOffset(1, gText_Buy, 28 * 8), 40, color, 0xFF, gText_Buy);
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, gText_EVIV, 28 * 8) - 16, 40, color, 0xFF, gText_EVIV);
	AddTextPrinterParameterized3(0, 1, 48, 72, color, 0xFF, gText_PC);
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, gText_MenuDexNav, 28 * 8) - 48, 72, color, 0xFF, gText_MenuDexNav);

	PutWindowTilemap(0);
	CopyWindowToVram(0, 3);
}

static void DrawTextWinFunc(void)
{
	FillWindowPixelBuffer(1, PIXEL_FILL(1));
	AddTextPrinterParameterized(1, 1, gText_ControlFunc, GetStringCenterAlignXOffset(1, gText_ControlFunc, 28 * 8), 1, 0xFF, NULL);
	PutWindowTilemap(1);
	CopyWindowToVram(1, 3);
}

static void WinPrintEnable(bool8 isopen)
{
	u8 dst[16];
	
	StringCopy(dst, gText_Enable);
	if (isopen)
		StringAppend(dst, gText_On);
	else
		StringAppend(dst, gText_Off);
	
	AddTextPrinterParameterized3(0, 1, 16, 16, color, 0xFF, dst);
}

static void WinPrintTime(bool8 isopen)
{
	u8 dst[16];
	
	StringCopy(dst, gText_Time2);
	if (isopen)
		StringAppend(dst, gText_On);
	else
		StringAppend(dst, gText_Off);
	
	AddTextPrinterParameterized3(0, 1, 16, 16 + 24, color, 0xFF, dst);
}

static void WinPrintMoney(bool8 isopen)
{
	u8 dst[16];
	
	StringCopy(dst, gText_Money);
	if (isopen)
		StringAppend(dst, gText_On);
	else
		StringAppend(dst, gText_Off);
	
	AddTextPrinterParameterized3(0, 1, 16, 16 + 24 * 2, color, 0xFF, dst);
}

static void WinPrintCoins(bool8 isopen)
{
	u8 dst[16];
	
	StringCopy(dst, gText_Coins2);
	if (isopen)
		StringAppend(dst, gText_On);
	else
		StringAppend(dst, gText_Off);
	
	AddTextPrinterParameterized3(0, 1, 16, 16 + 24 * 3, color, 0xFF, dst);
}

static void WinPrintCoordinate(bool8 isopen)
{
	u8 dst[16];
	
	StringCopy(dst, gText_Coordinate);
	if (isopen)
		StringAppend(dst, gText_On);
	else
		StringAppend(dst, gText_Off);
	
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 16, 16, color, 0xFF, dst);
}

static void WinPrintMapName(bool8 isopen)
{
	u8 dst[16];
	
	StringCopy(dst, gText_MapName);
	if (isopen)
		StringAppend(dst, gText_On);
	else
		StringAppend(dst, gText_Off);
	
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 16, 16 + 24, color, 0xFF, dst);
}

static void WinPrintBP(bool8 isopen)
{
	u8 dst[16];
	
	StringCopy(dst, gText_BP2);
	if (isopen)
		StringAppend(dst, gText_On);
	else
		StringAppend(dst, gText_Off);
	
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 16, 16 + 24 * 2, color, 0xFF, dst);
}

static void WinPrintAsh(bool8 isopen)
{
	u8 dst[16];
	
	StringCopy(dst, gText_Ash);
	if (isopen)
		StringAppend(dst, gText_On);
	else
		StringAppend(dst, gText_Off);
	
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 16, 16 + 24 * 3, color, 0xFF, dst);
}

static void DrawOptionsWinFunc(void)
{
	FillWindowPixelBuffer(0, PIXEL_FILL(0));
	WinPrintEnable(gSaveBlock1Ptr->gFlagTable.ftstruct.enable);
	WinPrintTime(gSaveBlock1Ptr->gFlagTable.ftstruct.time);
	WinPrintMoney(gSaveBlock1Ptr->gFlagTable.ftstruct.money);
	WinPrintCoins(gSaveBlock1Ptr->gFlagTable.ftstruct.coins);
	WinPrintCoordinate(gSaveBlock1Ptr->gFlagTable.ftstruct.coordinate);
	WinPrintMapName(gSaveBlock1Ptr->gFlagTable.ftstruct.mapname);
	WinPrintBP(gSaveBlock1Ptr->gFlagTable.ftstruct.BP);
	WinPrintAsh(gSaveBlock1Ptr->gFlagTable.ftstruct.ash);
	
	PutWindowTilemap(0);
	CopyWindowToVram(0, 3);
}

static void BuyPrintItems(s16 slot)
{
	u16 i;
	s16 first;
	u8 dst[16];
	
	for (i = 0, first = slot - 3; i < 7; i++, first++)
	{
		if (first >= 0 && first < gItemTableCounts)
		{
			GetItemName(dst, gItemTable[first]);
			AddTextPrinterParameterized3(0, 1, 24, 4 + 16 * i, color, 0xFF, dst);
		}
	}
	AddTextPrinterParameterized3(0, 1, 16, 4 + 16 * 3, color, 0xFF, gText_Arrow);
}

static void BuyPrintMoney(u16 itemid, u8 count)
{
	u8 dst[16];
	
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, gText_YourMoney, 28 * 8) - 24, 4, color, 0xFF, gText_YourMoney);
	ConvertIntToDecimalStringN(dst, GetMoney(&gSaveBlock1Ptr->money), 0, 10);
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 24, 4 + 16, color, 0xFF, dst);
	
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, gText_SingleMoney, 28 * 8) - 24, 4 + 16 * 2 + 8, color, 0xFF, gText_SingleMoney);
	ConvertIntToDecimalStringN(dst, ((ItemId_GetPrice(itemid) >> GetPriceReduction(1)) * 3) >> 1, 0, 10);
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 24, 4 + 16 * 3 + 8, color, 0xFF, dst);
	
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, gText_SumMoney, 28 * 8) - 24, 4 + 16 * 4 + 8 * 2, color, 0xFF, gText_SumMoney);
	ConvertIntToDecimalStringN(dst, (((ItemId_GetPrice(itemid) >> GetPriceReduction(1)) * 3) >> 1) * count, 0, 10);
	AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 24, 4 + 16 * 5 + 8 * 2, color, 0xFF, dst);
}

static void DrawTextWinCount(u8 count)
{
	u8 dst[50];
	u8 dst2[4];
	
	FillWindowPixelBuffer(1, PIXEL_FILL(1));
	StringCopy(dst, gText_Count2);
	ConvertIntToDecimalStringN(dst2, count, 2, 2);
	StringAppend(dst, dst2);
	StringAppend(dst, gText_SpaceCtText);
	AddTextPrinterParameterized(1, 1, dst, GetStringCenterAlignXOffset(1, dst, 28 * 8), 1, 0xFF, NULL);

	PutWindowTilemap(1);
	CopyWindowToVram(1, 3);
}

static void DrawTextWinBuy(void)
{
	FillWindowPixelBuffer(1, PIXEL_FILL(1));
	AddTextPrinterParameterized(1, 1, gText_ControlBuy, GetStringCenterAlignXOffset(1, gText_ControlBuy, 28 * 8), 1, 0xFF, NULL);
	PutWindowTilemap(1);
	CopyWindowToVram(1, 3);
}

static void DrawOptionsWinBuy(s16 slot, u8 count)
{
	FillWindowPixelBuffer(0, PIXEL_FILL(0));
	BuyPrintItems(slot);
	BuyPrintMoney(gItemTable[slot], count);
	
	PutWindowTilemap(0);
	CopyWindowToVram(0, 3);
}

static void DrawTextWinEVIV(void)
{
	FillWindowPixelBuffer(1, PIXEL_FILL(1));
	AddTextPrinterParameterized(1, 1, gText_ControlEVIV, GetStringCenterAlignXOffset(1, gText_ControlEVIV, 28 * 8), 1, 0xFF, NULL);
	PutWindowTilemap(1);
	CopyWindowToVram(1, 3);
}

static void DrawOptionsWinEVIV(u8 slot, u8 type)
{
	u8 dst[20];
	u8 dst2[4];
	
	FillWindowPixelBuffer(0, PIXEL_FILL(0));
	if (0 == type) //个体值
	{
		StringCopy(dst, gText_HP);
		StringAppend(dst, gText_IV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_HP_IV, NULL), 2, 2);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, 16, 40, color, 0xFF, dst);
		
		StringCopy(dst, gText_ATT);
		StringAppend(dst, gText_IV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_ATK_IV, NULL), 2, 2);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, 16, 40 + 24, color, 0xFF, dst);
		
		StringCopy(dst, gText_DEF);
		StringAppend(dst, gText_IV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_DEF_IV, NULL), 2, 2);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, 16, 40 + 24 * 2, color, 0xFF, dst);
		
		StringCopy(dst, gText_SPE);
		StringAppend(dst, gText_IV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_SPEED_IV, NULL), 2, 2);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 16, 40, color, 0xFF, dst);
		
		StringCopy(dst, gText_SPA);
		StringAppend(dst, gText_IV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_SPATK_IV, NULL), 2, 2);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 16, 40 + 24, color, 0xFF, dst);
		
		StringCopy(dst, gText_SPD);
		StringAppend(dst, gText_IV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_SPDEF_IV, NULL), 2, 2);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 16, 40 + 24 * 2, color, 0xFF, dst);
	}
	else //努力值
	{
		StringCopy(dst, gText_HP);
		StringAppend(dst, gText_EV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_HP_EV, NULL), 2, 3);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, 16, 40, color, 0xFF, dst);
		
		StringCopy(dst, gText_ATT);
		StringAppend(dst, gText_EV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_ATK_EV, NULL), 2, 3);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, 16, 40 + 24, color, 0xFF, dst);
		
		StringCopy(dst, gText_DEF);
		StringAppend(dst, gText_EV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_DEF_EV, NULL), 2, 3);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, 16, 40 + 24 * 2, color, 0xFF, dst);
		
		StringCopy(dst, gText_SPE);
		StringAppend(dst, gText_EV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_SPEED_EV, NULL), 2, 3);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 16, 40, color, 0xFF, dst);
		
		StringCopy(dst, gText_SPA);
		StringAppend(dst, gText_EV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_SPATK_EV, NULL), 2, 3);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 16, 40 + 24, color, 0xFF, dst);
		
		StringCopy(dst, gText_SPD);
		StringAppend(dst, gText_EV2);
		ConvertIntToDecimalStringN(dst2, GetMonData(&gPlayerParty[slot], MON_DATA_SPDEF_EV, NULL), 2, 3);
		StringAppend(dst, dst2);
		AddTextPrinterParameterized3(0, 1, GetStringRightAlignXOffset(1, dst, 28 * 8) - 16, 40 + 24 * 2, color, 0xFF, dst);
	}
	
	PutWindowTilemap(0);
	CopyWindowToVram(0, 3);
}

static const u8 gPos[][8][2] = {
	{ {48, 64}, {120, 64}, {192, 64}, {80, 96}, {160, 96} }, //主页面
	{ {56, 40}, {56, 64}, {56, 88}, {56, 112}, {184, 40}, {184, 64}, {184, 88}, {184, 112} }, //手机设置
	{ {0x2E, 0x1E}, {0x4E, 0x1E}, {0x6E, 0x1E}, {0x8E, 0x1E}, {0xAE, 0x1E}, {0xCE, 0x1E} }  //查看个体努力
};

/***
 * 0 == 主页面
 * 1 == 手机设置
 * 2 == 查看个体努力
 * 购物，电脑无光标
 */
void ChangeCursorPos(u8 spriteId, u8 selection, u8 section)
{
	gSprites[spriteId].pos1.x = gPos[section][selection][0];
	gSprites[spriteId].pos1.y = gPos[section][selection][1];
}

static const void* GetTiles(u8 id)
{
	return gTileMaps[id].tiles;
}

static const void* GetTileMap(u8 id)
{
	return gTileMaps[id].tilemap;
}

static const void* GetPalette(u8 id)
{
	return gTileMaps[id].pal;
}

static const u8 GetMode(u8 id)
{
	return gTileMaps[id].mode;
}

static void MainCB2(void)
{
    RunTasks();
    AnimateSprites();
    BuildOamBuffer();
    UpdatePaletteFade();
}

static void VBlankCB(void)
{
    LoadOam();
    ProcessSpriteCopyRequests();
    TransferPlttBuffer();
}

void ItemUseOutOfBattle_Mint(u8 taskId)
{
	gItemUseCB = ItemUseCB_Mint;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_BottleCup(u8 taskId)
{
    gItemUseCB = ItemUseCB_BottleCup;
    SetUpItemUseCallback(taskId);
}

void ItemUseOutOfBattle_GoldBottleCup(u8 taskId)
{
    gItemUseCB = ItemUseCB_GoldBottleCup;
    SetUpItemUseCallback(taskId);
}


void CB2_SpecialPocketReturnToBagMenu(void)
{
    gBagPositionStruct.pocket = KEYITEMS_POCKET;
    SetMainCallback2(CB2_BagMenuFromStartMenu);
}

void CB2_SpecialPocketReturnToField(void)
{
    gBagPositionStruct.pocket = KEYITEMS_POCKET;
    SetMainCallback2(CB2_ReturnToField);
}

void ItemUseOutOfBattle_MegaBox(u8 taskId)
{
    FreeBagItemListBuffers();
    if (gTasks[taskId].tUsingRegisteredKeyItem == 0)
        GoToBagMenu(ITEMMENULOCATION_FIELD, MEGA_POCKET, CB2_SpecialPocketReturnToBagMenu);
    else
        GoToBagMenu(ITEMMENULOCATION_FIELD, MEGA_POCKET, CB2_SpecialPocketReturnToField);
    DestroyTask(taskId);
}

void ItemUseOutOfBattle_ZBox(u8 taskId)
{
    FreeBagItemListBuffers();
    if (gTasks[taskId].tUsingRegisteredKeyItem == 0)
        GoToBagMenu(ITEMMENULOCATION_FIELD, Z_POCKET, CB2_SpecialPocketReturnToBagMenu);
    else
        GoToBagMenu(ITEMMENULOCATION_FIELD, Z_POCKET, CB2_SpecialPocketReturnToField);
    DestroyTask(taskId);
}

void ItemUseOutOfBattle_LegendaryVoucher(u8 taskId)
{
    FreeBagItemListBuffers();
    if (gTasks[taskId].tUsingRegisteredKeyItem == 0)
        GoToBagMenu(ITEMMENULOCATION_FIELD, LEGENDARY_POCKET, CB2_SpecialPocketReturnToBagMenu);
    else
        GoToBagMenu(ITEMMENULOCATION_FIELD, LEGENDARY_POCKET, CB2_SpecialPocketReturnToField);
    DestroyTask(taskId);
}

#undef tUsingRegisteredKeyItem
